emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ELPA-diffs] ELPA branch, master, updated. cb753c3ace486a17e1f3fbb3cbee2


From: Stefan Monnier
Subject: [ELPA-diffs] ELPA branch, master, updated. cb753c3ace486a17e1f3fbb3cbee29dfd20ae68d
Date: Thu, 15 Aug 2013 04:13:02 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "ELPA".

The branch, master has been updated
       via  cb753c3ace486a17e1f3fbb3cbee29dfd20ae68d (commit)
       via  c45346a3c823eaafc09b96d2c33ba945a287346a (commit)
       via  af5a17495f80e22dae84f22f2b8b4b1105ca102b (commit)
       via  57560f2651584873760f4034259935c3a568f1c6 (commit)
       via  6817d912be60c8d261856ee7c0ce959561e17f32 (commit)
       via  e5bc365387b8c37f425e25e233f1528fa20c369a (commit)
       via  4861427a5a8b64fc6ae555a140129c27a1d62175 (commit)
       via  fae643a95ed3ba2cefbe70c94d16da7b17877dca (commit)
       via  de7288845c1310f3e6f79b8e5cff7415a894c748 (commit)
       via  4faa2623a68e90c3b817bf83f2ff1785b85684d6 (commit)
       via  06955397d6103651fc01022dc45174b72b4260dc (commit)
       via  fb883784a1c773b4a1e43d2aff7658b9129eff00 (commit)
       via  28daa752f9f5578f989985ab3de02a82792c66ef (commit)
       via  bc5c2a2ee2b993a18e8e23ed725829d403508753 (commit)
       via  6f033f25424768df826b2758e0cfdfa398362299 (commit)
       via  4089d1cdb85a55d8e5add426a9c07402ab6ec3a5 (commit)
       via  034e6eb9154a367f0692f7804f48217a6834620f (commit)
       via  3e060d98a5cbfb9ea167b9e2e1bb505561d056fe (commit)
       via  714dca50644c75884d9d90f10328c7a12e02cdcc (commit)
       via  c6ca082c191cecf616fb531958ef390f148bf6d8 (commit)
       via  9e7c6bd3c54ee17bdd639d27184a2d53681ab630 (commit)
       via  1c53de75e0acd19d61ad45a91b32c183948e5128 (commit)
       via  ef861dedc420453d91b348107633a3043b371be6 (commit)
       via  b63de685c2daf93686e902d56f8aca424ec15706 (commit)
       via  3334309116496707a52b48ce7f2ce4553a5ffbc4 (commit)
       via  f546cfdd8ede04c5574b3348c7458bdd15497321 (commit)
       via  fe5d11f011a2e4b5958d1dd698de7afd10c2f212 (commit)
       via  908c6f6e89af8b32b80591bb0095de86a9441156 (commit)
       via  c573b74da1e9056f8a3fbeb826600a8d254c5445 (commit)
       via  e8bb6cc80417af65d9a92cb871cdc4b7283b0eee (commit)
       via  8c9ef10eb295dbbee28f98510c89d7ef1c8d333f (commit)
       via  98ffa3dbf0e0d1728ea17dee5c09728163dfc8f5 (commit)
       via  a11ba885a58db7092b2f15d181f4c2a28b8ba08c (commit)
       via  0b786f9e8b050c397ee0740ebe955d6daaa9e010 (commit)
       via  2cbe8d9cbd9151ca94b970eb567bba073fa088ff (commit)
       via  764d2aa4ba50081adf69408e62d4863905b68b7f (commit)
       via  900a78dbaac691a6a852eb6e19bff16370de8add (commit)
       via  1d28760268f22306673b718bb3101c4121699685 (commit)
       via  100912d9c7a77d6349023a6cf91da05dc9f6e7ea (commit)
       via  a671e2ba473eee74cf385026be0f919a7de0cc86 (commit)
       via  d2587c44cefd96b52a27bbc296cb8156eb2ad773 (commit)
       via  b869cde68a1cae6f7d81bcc2bf0af88dc1c80f79 (commit)
       via  7499a00484fae37d8b6cc75861aa08f26418788a (commit)
       via  e374ba2ca46113722559ba0f87204530ad8c9d47 (commit)
       via  9150eca78f27925ba72389e830c32f36b3368784 (commit)
       via  d02dd88006c5584e434e7f7ca9f4954ab5f8b7ee (commit)
       via  55ee07cf95e177ce1a5e3d23a53d354749314846 (commit)
       via  6f2d10ada20e0854033019c38bfdf74a57a34cd2 (commit)
       via  11bbdcb8cd323f4a22793a4ded61c8c3e3396aec (commit)
       via  d21bb454dcfacda8808b596e4bca85a53a99eabf (commit)
       via  4456662366342b75413e2d7b63a3d229220211f6 (commit)
       via  c1f2813c30433d642f9a3c73b4be3d1bcbc03c93 (commit)
       via  9b1ed514d64f9adff97f1b3b75023ad7ff743887 (commit)
       via  757ae4bcc18549e85b3131664ca3639a759ad162 (commit)
       via  c50f3d1d9db63bcbea3f02036ee17ab0d7511be0 (commit)
       via  e48289f90d9b8ffa179a5505970421136ef42150 (commit)
       via  5c7e8c516f577c6266b05e8a09d4ca6089295f06 (commit)
       via  cce396a2885f4b91edb4383d85ecc9e38a7533db (commit)
       via  ba08184a0dfba0b6f988321fa83f0f061ab0b8eb (commit)
       via  3c69aea0c267e7bbadd5e35eb6cab54764c9d91c (commit)
       via  2560f92866a1f15ca393b7ae330d755648b2e786 (commit)
       via  0d1b276e2240bb765908c895cbce862f9a54b9d4 (commit)
       via  068a36adff25e244dcbb21aafb953fc3b66c5853 (commit)
       via  4c735454d91f9674da0ecea950504888b1e10ff7 (commit)
       via  41b1eea33bf85095a2211e8963b0b307ce20147f (commit)
       via  409bc6a7d16a9edc3337b90ca878acc3f1e3ae17 (commit)
       via  4508b7a70e18da25d20cc2ac471086fdd51acf2a (commit)
       via  1331b718431597d4dcf2bf432ec642b456fe408b (commit)
       via  3d7683107180203654e0da80ed556240bc94c2b3 (commit)
       via  837c8899e6957a9acbd058d3c3d92bc165956f07 (commit)
       via  f480808a73a2e60c2480bd89825d0af60b75b9fb (commit)
       via  d159a22470d500c7095261266e7bff9139bac2fb (commit)
       via  2e9af64d0fb19dda43da7ed90df825f3b231d6d4 (commit)
       via  0a0e8c6fec890b2ce9823da234f7668e55162987 (commit)
       via  a254018f99467ad86d0bd6a798b9ef88ca92e371 (commit)
       via  5e0b93a40db3299f32ff6861906067ae7f881607 (commit)
       via  f06ba5a6a919049f169d7507433b8f4f85b5b90c (commit)
       via  6e37b4c18e63464a544941f6968a4b063b4eb16b (commit)
       via  dea7474d33b5164c40cee3e557eb287913da566f (commit)
       via  7d557877cf536db6639f6598bcc87001f9f59c11 (commit)
       via  81fc9e178f2a5a15b8253bcc3c70854dc9cd7736 (commit)
       via  c1dd7729321250407f804f0fe26939ea141f6e14 (commit)
       via  27d3053993f73460b3ec48f4ae9779577f3c829c (commit)
       via  d4913b4147167bdcde22b44e4f0ec74f265e562d (commit)
       via  9add1d8d3339153a5ec121a47e89bfc3ef1b1002 (commit)
       via  ac6121486845963000096bec0d81b81742f13702 (commit)
       via  76d189f52b6965447e6b0451fa62181a980fa6fc (commit)
       via  61e87e829103cc8356807f3dcd77a5bc1f0e09c9 (commit)
       via  f5ee458241950b42443415e5bf42eab182b100ce (commit)
       via  0b019b223ccd5cae67211ae8498091f186148477 (commit)
       via  1c8600b4ccc326ea8046e22baff403d7918b14d7 (commit)
       via  baa85ed19e057e78d24f001f9331d31575c8c688 (commit)
       via  eda08529b0f8cecb84c57ced2e0776524c830a8b (commit)
       via  073e167270d6a968fef45c1f0d20aeedc062fa52 (commit)
       via  ed098081e740a9db75af3ea8f77edc3191de3d58 (commit)
       via  947aebba714790a8d5be48987f32af1a1def2bbe (commit)
       via  a696ca3aef5df9260ee2564b0c0b77d5b5c3a8a5 (commit)
       via  0fd01279dff979f8831764d96dd7d9a1f046bf29 (commit)
       via  1d919104f29f8a5dd9f9f5e09b6c4d168a43e3b5 (commit)
       via  4c4829d664ab875f7cd63061b22b68d58846e19d (commit)
       via  0a642d5d31a8e0e22a4b2b2a48dafd6393b81aa9 (commit)
       via  6f34d76541a64d51ae40ef0f5864072c7e677511 (commit)
       via  ffdfdad41eb066a3e967efb25f05e4cb776a20bf (commit)
       via  7c61476f696330e560d5d868fe8f779cd36b113c (commit)
       via  152bc897170749a4fb24ab0f0a0d32dd5523e4f9 (commit)
       via  92ac3d0ef663bca26abbda33cc20a02a58b1c328 (commit)
       via  40752cef83b8b7fbc8d662bd4fcf532b2250b2aa (commit)
       via  caa962bb9d4ce1760170fd3da1d4cdf653060204 (commit)
       via  a982f0fe043c31aca1a11a663c41c33b76ef0c19 (commit)
       via  b7f831babd449ba7ed04f1e3a7e82ff178af2c18 (commit)
       via  6a095e308b15d4dcc2358d8a2a3f88e440433a24 (commit)
       via  320a9d09cb3b9b484286c4bc1290d4887467d58f (commit)
       via  8563865558b7cf54956906c8c7b5c0dc98bced7c (commit)
       via  f3813a6acf3b795ac1b0e261b5c769c3791b2a87 (commit)
       via  f77e02d4f996749f51bbc4c035c0e0d7dc16bb03 (commit)
       via  b46447516d13fe5b56428215b8c9d6dd35451375 (commit)
       via  78f8b974a8f68ebc4258d5b1fcbf4b03f2223501 (commit)
       via  49436401cdcb18029dd37bb41c5c8f28ffe69776 (commit)
       via  988cf9d8c21499ebdec0eb6d15ba4d92d5a2830d (commit)
       via  db19d03474dee277158b3ed5de088aee9d152913 (commit)
       via  a2724d172a55091de641baba1b6382b2d24668de (commit)
       via  4b909bfb2baed9afaf2762b0b13b9490ad4bc246 (commit)
       via  898d24473460332ab92bea5367b93ce6b8aa86f8 (commit)
       via  5c3f8acb7acb3214cf693e9842c5288fe810c5dc (commit)
       via  ae0e0c73b0bc0ad447d34b4900320e4f934de377 (commit)
       via  81f654a44addbe4376c18c9f7fc401b8103a606f (commit)
       via  d5837b4f4aa8c9e393579432afaf14716b608309 (commit)
       via  8774bc9596333d838cd941e0d8b27065b8002894 (commit)
       via  8dceda389115b397de48becc4b68a64f4dc4bbab (commit)
       via  ed643b908e0674ffc1aec9af2df5380ddfcedbb8 (commit)
       via  7e80033bef50bd077b335543275736a552889104 (commit)
       via  da7ddff57963996119c50d75b89db70fc83a5888 (commit)
       via  6422b3e7efb554bbfc8b9d9f051402d9097573b1 (commit)
       via  33d2acd2a8fa3ac7e6cb5f712baa8507662cf2c8 (commit)
       via  8a23e481449111d0050e0250039ae8a0558807c0 (commit)
       via  0259e7b94c7c6c00072454ade0716cb5d3646dbc (commit)
       via  b446a994bb90e8a62cc7ff362c8e0421ef9c226f (commit)
       via  ed75169bc3f458a25a192186c0d05bff8a54be36 (commit)
       via  fa89135e030bdea584b9c3f87992e82f6b3fe1ab (commit)
       via  50293ad01f7ad9e1280a0b0845545516260f4505 (commit)
       via  4ff66327158ede1b470fc4616db1b68d9f561cd4 (commit)
       via  83cbc7d328415bdf7aedfa02ca3017d5cb16dd11 (commit)
       via  9218392f6e80c0f24979259721b23e9e75d61002 (commit)
       via  3ac29fb27bc3809d04ce54f773dc5b3e3ccde78e (commit)
       via  d260c2486281f630301925a1d6d2ebcc16bea1b8 (commit)
       via  42e431dc7f4a22b476884139aa4d8b73aebdd25c (commit)
       via  36108c9f82d401113c2b87c18576e9835bd44e1c (commit)
       via  fb0e4cf536171c8faedd1df612563a327bb7baae (commit)
       via  bcae310be39553776055e0d8bc6289555f6ed736 (commit)
       via  d0963a5db772b31f77f8a34700cfa401906302fd (commit)
       via  8427b8f1edd77234349930f440b2f03bf519221b (commit)
       via  f5e957045bb1f45f2aef8fd2ff43828e8a19891f (commit)
       via  e7dc3a7617d84b0f6955d0921a9143bbff2ba4ab (commit)
       via  8ec2c2db395f14ab194cd585150b8cbc6dadf42f (commit)
       via  35e38bb102b04fa59f64e9bfe7b693d2082d748a (commit)
       via  99efa0e85d46f3dff2185d5439704aa809403084 (commit)
       via  cdebad70a0873c0f9eca7b572aebe8b9a6f203e2 (commit)
       via  3a0a1eebe2be8f71c9541ed11a8bd79343cedb7e (commit)
       via  177478df812600d37d41b7f14443c97a42f9ddd0 (commit)
       via  1c07663062f3456c64f6d0f2554e505b7815c921 (commit)
       via  5a18e987dd87b33d1e8c8250d08f6580b1eb1737 (commit)
       via  eba32647fcbc74480d8955cd26381e3bdc7cf96d (commit)
       via  43d9131e07bceb60ab136074b1d32becb5be0c02 (commit)
       via  c58998e8e4ebf93434c77b5b7b2691213a3533c8 (commit)
       via  4b2c71f7919166c4a37487c8859285a1f49f8a07 (commit)
       via  c985070615a9be6a350708855fe2454906317c78 (commit)
       via  3dd60d13c7bb4af33d1a0b0ff320d39039cfe9a0 (commit)
       via  509f231cb803209017a31299343c2a3317fc2a4d (commit)
       via  29fbc711eda6a3c43033ef4e8c3a4603aff3db87 (commit)
       via  24c73b930aff562cacf9c068b7f1c9ab6521eab2 (commit)
       via  9a2dba0b6ef2f9b6a0191c8a43c9dc083d31b804 (commit)
       via  6d979b80e37d66b83172feaa1cdb8b5b994619c0 (commit)
       via  6d14ffbfd6c1dc061c291d630ed63d3b2241c043 (commit)
       via  809c7833579de5217069c6e678c30e0667c22a9a (commit)
       via  06ca7849f29189687aa380a2c3d9c84c7859aabe (commit)
       via  23ed20ed236761b2aee517bca01810b9324698de (commit)
       via  0970c3d32dc3aff696f41d9a4fe9050c2318d65b (commit)
       via  56a1a36395f0d1bffab96532d71e4345eb8076eb (commit)
       via  1f30a34741c61f35b18d66b6b506bc2a8242f858 (commit)
       via  9bf653e045719b0823de5c809bcf0b8751f8c3a8 (commit)
       via  9ff7b4160ffc4d7639f8b184f58d0f5a4abe897a (commit)
       via  1868d5c64e9fbc764bb668fd8077b6f4829464b3 (commit)
       via  da32a6a4e9fd28006e4a53e99250e80587cb50bf (commit)
       via  38aa1ca2f88607c8cd9f9b5a14bf0dfadadc5546 (commit)
       via  5b0f5b93f6982545561de5d7be19b3fc291a0814 (commit)
       via  3c666787bf15c85809ca0c4f3813169b819d3270 (commit)
       via  f18a8bc3004da4382bdcfdfa4cf515853b0d2e1b (commit)
       via  acf66fb09d6bb44e00e789994fa0bb916213459a (commit)
       via  48afb6016c87bd72ce6c14b1947b2c22a8827f66 (commit)
       via  dd7ce94b2bb4a8967cd442c601cb4bcb765306a8 (commit)
       via  1e34bac4cc864071284c40b7a0d06cc4b039890b (commit)
       via  dae36cc520cf60960d0d650ff09c09ecf5525d3a (commit)
       via  72fbcfaba1f40b692845a38d9c3c36d8338de59a (commit)
       via  1925479b9f782bbe339e7f9e80653cecd6f12f2f (commit)
       via  fecb101033b11233cb3eb0a2b288665f5c1ff1d1 (commit)
       via  72a824ffdf93287d72a0479a6a210ad0af46724a (commit)
       via  c2fcc867f9014315646f0641069cdd3b614a8bc2 (commit)
       via  ab9d10a7fc525a4ffcf3c90b218484c4fc7089bd (commit)
       via  65a07086a81663b372c8589da4a966fa672956e7 (commit)
       via  32b8bc35f054b315f8ff2bffc6489589c43d5964 (commit)
       via  ecf7af6c22f3ba8bd189ebb3b3f86d1bb85f7441 (commit)
       via  78d6ef179eeec28502ff821f2a28d7ba641adebc (commit)
       via  7a195c6bb28b93a12a73a51c445e35cd017f2c68 (commit)
       via  9f69658a364991b0bbae940eb388dcc452aaa8c6 (commit)
       via  6009938d5bf83ea53e59831feaec5af549d0d0ac (commit)
       via  52a81628a9646f9aba03528b26efc5c6cb4a08f2 (commit)
       via  d79c8d053db68cff5d718b64e44b0b31d9d4b948 (commit)
       via  06270357092d267fd65e501a37a15e2f5e306e92 (commit)
       via  408c2e07e8064a5e6d7486ecafd19b2ee8a9ac7b (commit)
       via  d5f74fe53238d8dbf55dc8450b27b491861dc74d (commit)
       via  c0fefbb2b457a87c271fdd3a91d907f15d8c1d21 (commit)
       via  3b953efb9a7071f7dfb34906247e2a8e554fbb45 (commit)
       via  48ecab18628772451b8870fdc5ac4587cd7be3ba (commit)
       via  f2c4167c3371da3632fc264a6fd111d9be4ffaf4 (commit)
       via  a2cdaf107a29ad6c23ba24ad60c09411b4e06a9e (commit)
       via  6ffcecc4be2d87a0cd9d061937cbd6083aa99666 (commit)
       via  f923ea8dc00419742ddd2745c5ef3b5d0c20da07 (commit)
       via  393453f1e22a10bbe7c56637500db8ff9223b30e (commit)
       via  d121d4ece2a4e973347db3404071419bf1c19e63 (commit)
       via  f219f7fdcc19575c7890b7a7405bcdd1dd993881 (commit)
       via  292684bd46ca5c9eb5a4ee6942b92f92896a716e (commit)
       via  25f2c535458972bb1309f7c602454bb56b656fd2 (commit)
       via  1043ae9a1eafc6f5cb3ffb60d1410a16afb8e2ff (commit)
       via  ac36be9b2ca1348cbd912ad2938d2c4fcc88b64c (commit)
       via  ba3e433b5b0c78ffe08637a167bda549d1077527 (commit)
       via  5f961af80f5ca612dd74adace3fdcd3644a8078a (commit)
       via  9e572a0823cd101c9424652c7bccd510d60e5743 (commit)
       via  cb71facbe560a5155350dcc0466d4d47b8fa05dc (commit)
       via  b330d2ea8468fa102950f781205ec98c7942f44a (commit)
       via  4cc87816c157ea2831a286a2264a1f259c535cc2 (commit)
       via  34875c88d73c92ca009c9d50e1d85aa9eabf7f32 (commit)
       via  fc4844b21da115448ddabce87735e0f6f69b102b (commit)
       via  afc950fec4b6b9d7c8e6ea48caa22cb36287c869 (commit)
       via  f08f6f6d960dec80eb8bf9749856e7364cc1bbf1 (commit)
       via  d861f1d075faf63ef11af087b0d53c19b08867da (commit)
       via  9108df1d0052c70998dee701c58abfb74e36c0ed (commit)
       via  7331c6efd2c9569da8aeecda8d64a421a157b5dc (commit)
       via  739760229c25979f00456ce62b0bf729d6e6fcda (commit)
       via  8bf39d5e3ee15eb9c4fd111eb08e081e2cfdb513 (commit)
       via  0b6d832a8d1a7db39b1d6fbd877bb5139ded6c06 (commit)
       via  9e1a4d8a3b4b738e238ac6a385ab9f1434f805f8 (commit)
       via  9b1f9009d934ec917bf4770518df9dd5b4fe2f1a (commit)
       via  d3dda607ca2c34ddfed658ab52833ec8741d7c10 (commit)
       via  a97240339cf2fc42c0df5d66e0602e8c49e6e9d7 (commit)
       via  6d9d3032e24eeb856115b6309b2ffbbbb8dbcf38 (commit)
       via  8b7d5ff1768dc573b9d2e64d1fc8a5973de163b9 (commit)
       via  cb0a58684509ba5d3546d7d08a11b136ca294c11 (commit)
       via  ffdeedf11ae57e976c8bc164ebfdcf1aff869a74 (commit)
       via  f713d6fb3b46417d500d2836d9b6aa8df2093e54 (commit)
       via  38585ff9eaf38ed0f38cccd9b8943204ee059652 (commit)
       via  fd16a6299ece3b9b0c85aaa1b48ffbdf56541270 (commit)
       via  1c3b98ac36bda12408d94b27092dc3b47e647593 (commit)
       via  aebd60c8865fd914e45a05f1ac5ad86988404e04 (commit)
       via  5309fdede51856423e09f3af021e01876c286109 (commit)
       via  a28e0c3b186c123b158749de2d38815757d20962 (commit)
       via  63f135e2bafcb6dfd9a8014045f8e89d46e2f707 (commit)
       via  3eb2651ce2ddff6f2dc83720eb15ba2617457b94 (commit)
       via  02f64d8bb616c81ff1c422c8130097a712ad559b (commit)
       via  67738bd56bdf9e3c3cd89bef68c4d4a11b220719 (commit)
       via  e90d7c659dd4531185c78dacf376241de32fa7d1 (commit)
       via  81ecc1dde62a4ed0c914ee206b0bf891e6425960 (commit)
       via  dcfe4ddaec667cd8af1827e570bc8b428ad5428d (commit)
       via  390b63293ed70673a840dcf52dd94041f242ca10 (commit)
       via  729ef3e0cc7d1ebb0a3f0461dfa542ab24d48013 (commit)
       via  ba49dd76036f659791be3fe78a093ec97da88b47 (commit)
       via  2ac3a72df85a0827017af119da69a3102f6c28d2 (commit)
       via  2621fccb238fbfcc337cb853c2fba6a57c42d300 (commit)
       via  e861ebcbf4bfc303be5ff3866b77e791e14a08fd (commit)
       via  c7999fae536e0cb3af675e1ba308e4ad13497c01 (commit)
       via  2f274258aeb4a66e16d3f90bec40b00b6f080dff (commit)
       via  cdd25bb4c7723ee0f10c59f0afd8e7a75fd4d031 (commit)
       via  807010e5ebfe9e3501e679f17cfd5ba3217db870 (commit)
       via  c3b45e3d3375f8ecd7f30060432a0265ab93d2db (commit)
       via  ef7de01af0262c366b3e7fffb615bbddd43a1e88 (commit)
       via  65854534288acb77e47bc45ed407a8e282332438 (commit)
       via  eca4241cb8f0f972b12ec0eda1537605dc28458a (commit)
       via  624f5e661849ac91d53afbb333403114eee4ecfb (commit)
       via  bfb482fd6b4ad4c14ddfd23546f44df628b0c1a7 (commit)
       via  6d7b67ece15c78c43ff5ef1cca556def20356bb1 (commit)
       via  fc2fa199996b6253bf510308569c7afe8b009d2b (commit)
       via  214e28d45b679b6538f8206d6af7be6935dd3038 (commit)
       via  f66b9811b330f1748cb0093270345291f88419a8 (commit)
       via  cd4a73fa21cfc6764a21cad41647a93954d940a4 (commit)
       via  d6d936c7a272ebce700be845d7e54e7d917afdec (commit)
       via  91a2895d72470c81e67bf40227bbcaa615d8894c (commit)
       via  2273af9f6bc85e7244f5229d9a53ae5a1d197eb0 (commit)
       via  5f9278407351f5b8143b9f989e152723d1fbcc40 (commit)
       via  a13e76c84739db1849169efbaf6112626ce720f5 (commit)
       via  d74c943aad4b5957ba22fa22ecc026a36c5c1237 (commit)
       via  0ce35d2e0edb36f9616d15beee26516c373109d7 (commit)
       via  8f1b568741b158db05b9d7f62960a42e902f80a1 (commit)
       via  291285e9edd45a4e8a04807779b2d8f906c8c4c1 (commit)
       via  920957f2004997dbe1f497432f6728c30c3da394 (commit)
       via  07062a9b12e63b3069d9790149873510e1c64c36 (commit)
       via  7e914a0ae0b19531bb7e0040e01943d2f3079fa9 (commit)
       via  30a7a207c3f07344e98a9b5adccff89eff11b278 (commit)
       via  74eea614e64b29d0b00f0df6c3b1946014ec7d23 (commit)
       via  10801fc4e6f4c42069b0be08f372053a8e5f7c81 (commit)
       via  273978d3395868d4aaef8001cf5f15d17b63feec (commit)
       via  69b1b57fa8a9ecbb80930d028be30aaf0f934050 (commit)
       via  c1d27be5a4b47ff5a3b36386531741dd7cf177b9 (commit)
       via  d2b33b2a37726e5ccb36c9eea68ee3446d442bc2 (commit)
       via  7c55d29882ff67a19368bab5ed8bf93082a8377e (commit)
       via  c1d78d95db50af380f53f4b4c0737434e41ebf1b (commit)
       via  7450e102b1108ec2edc319a4d61ecc6f633be961 (commit)
       via  843a78d2a4fedd18386510ee78152d31898c74ee (commit)
       via  ecadddfd280bbd9239952ea06e24b995a7f57fb2 (commit)
       via  3baf07adedffade081703ce45059b4a3182e0865 (commit)
       via  1fa14bb71df4b0fabc123234a517533a19077f6d (commit)
       via  f4ae1de92f40837e67af46378fd27d02c0e6bd22 (commit)
       via  086cacd47c24f1a8707a82689d5dec49656f7562 (commit)
       via  ec0427470f8fe5e2a10c7658b8689852afe2a890 (commit)
       via  843455d84ba4de1140232b4f540fa50105081e4f (commit)
       via  7630a844c3453409825364e0ccb1504b1efa4b08 (commit)
       via  eb89f06d7e4329f5041dce998f2e093259c6b4ef (commit)
       via  e378db4d306907e8af78bb1c766d5dbddbbbf4f2 (commit)
       via  8b78584fd26a465f66ecd3c32c5f4106823bae51 (commit)
       via  bc1e159ee95c120041c972b147bbe81a3f178bf5 (commit)
       via  139014fb75e81fe1d6f355543d85de898e61d555 (commit)
       via  bbaa2843a38bd689950e9263c4f4ba5747eb53ed (commit)
       via  a310dfc91eec38ce2bf3553ef5bde2fe532b4505 (commit)
       via  40dbc6935b8012a62e6f6af8048d5849a64edc6f (commit)
       via  803ff3611c32b0cf677f565e4d501a686bb705ae (commit)
       via  540578b749644cd6f4d97fc137dd9fce907dae68 (commit)
       via  a0a66f2f6a1edf5368251bca7e76cafe2232fd1f (commit)
       via  2583c1b67ff8abe6341bc7a1fc661eb40d75694a (commit)
       via  0fce282ff01c002509443372fec2279794f89cf4 (commit)
       via  297244fcfd3766c1cd741b90d630d85f9d9a0258 (commit)
       via  99ab8c8ae50995afced95712e11bfa21ef02c71e (commit)
       via  3c5871ba43930d0aef427559e643b8ba32aac043 (commit)
       via  379547c62aa3dfd2b20474a1a68f42d3df0bdd72 (commit)
       via  1be7648c0248bb95505c2c26b1bef70c2cf38ebe (commit)
       via  88ada6dc4f6228bdd03ebc4eb0675ab54d79d387 (commit)
       via  a2e8934cfadb242af6df209703311b062d72d448 (commit)
       via  6b3f092e023313c5a00c5cb1796b4ba78039e779 (commit)
       via  389992b77b25bfd1cb7e4492965ed8a5f1ff852d (commit)
       via  fa107c54964494dbe5c4b0e850c34c0350a4160a (commit)
       via  f0392a63145a1935e97092100af687482e64aaa9 (commit)
       via  aefe34a40d41b3ec57c86e552b0c3e9f29cbdcad (commit)
       via  38e5c5efbdcb7606da9aa854e1603323095f5db1 (commit)
       via  86e1a266379d22948aa24502aa744e6b4762c4ef (commit)
       via  7a0ae5bc110f1082dcc24f63aa0feae9d420a65a (commit)
       via  1237b491508e17f120b2bf72ceb7e08e772dc201 (commit)
       via  ae1fdace89cf97de3bcafe044b8724c9c4d76028 (commit)
       via  511dd418fb002dfb636ebf9e0b05fce4c903ae34 (commit)
       via  be3031f0473ff47ed045e81c141b977af937b740 (commit)
       via  5b87a3e075ef777a8ed44245d5e05f35cf1828b9 (commit)
       via  9947b8385420010495fad05bbcd42d73a46b49c3 (commit)
       via  b81dc1690b3cfd4153e7570bdae77894fbc9e0fa (commit)
       via  89d510f78de51c2300596577a5469428a105ccbf (commit)
       via  a1e6f9ca64d7fc81c000b03b77d5d43497aa7dd2 (commit)
       via  3555767aeac82d0f3d9f85ae13078207927a99b2 (commit)
       via  1b19cbe7b746467b97927a55078f0a7465991e64 (commit)
       via  d529164cfe20b65d1389880981d4ec1f6fb86acb (commit)
       via  67d7e79306ee83ec15b8711c092e616bf1ba2fe8 (commit)
       via  2f5168af1b4cf2ad6274ecc6fb36cc0e2b1670c5 (commit)
       via  acbeab6ed191f7b7013c7d5b0d3bb2e230fc5673 (commit)
       via  061fde1ff9d88407908c349146fbee568bf0b632 (commit)
       via  0a84731c4fe8b85482ba10637def80b932b112e9 (commit)
       via  45e8cca8bd8ffc6f4d22d38d18d04576899ca7e5 (commit)
       via  7b9dd8ff21072c833ec4838868bb7b69a1a6d955 (commit)
       via  be599424f028dbde8d37e81d5dcd8e9737a6ffa2 (commit)
       via  52241c5544294964b9e9d2f0b61ace82384779a4 (commit)
       via  be0394e00f530fdd999f13e3d653b3eba8977434 (commit)
       via  fef03725b09448959075b63b73c7e6ebe14b3a27 (commit)
       via  6fb5901f57f031cf68280c34e31d455f7535546d (commit)
       via  5efdc9a2d8bdba4515390e8143fecad22ae28cd7 (commit)
       via  bbb15a4a6c03a2e64ca6037fddb92e9f3df3c1c3 (commit)
       via  a54bd05a8f35ec42abf22dcca541571ef2f21e1a (commit)
       via  2619e05769df4b48c56bca513e8a371cf3d45231 (commit)
       via  cca2fabf40a165b196b436cf371ebca7eaec7707 (commit)
       via  c3ec4af58c12c787a8e09cdcd74b986e93e59964 (commit)
       via  47dd40b100ecae0deef41a6533b402fec740e65d (commit)
       via  b65328cc09e7c802ae29142ec5e7fa1f18ecacf1 (commit)
       via  1482463fbd97acd81b29d9170d27080a2632de04 (commit)
       via  29d8f2f1b8bd3d4dc452060e06ec407b0a6a8cf3 (commit)
       via  0efcdfe447db605ec188f80ae99caf0a1b48c598 (commit)
       via  d29b171b812893b30fa0b86eebbaf548518992f9 (commit)
       via  b02f4a0d72d0e2087038fe891e2580c4505415ef (commit)
       via  1303cca62f4ea725baf6e2d8c75ddd9578515ac3 (commit)
       via  f34455fd511bb445306b4e333f2c2845ee4ad96d (commit)
       via  f26abe1c150264162676826cd48a8fed87f3ada4 (commit)
       via  7ea106e70cd528117afb6764662a5832cc0a71f4 (commit)
       via  99f7a96c3e41f3868923d9278398b573bebfd122 (commit)
       via  7f15efe5d93ba80a715150ae9e6a15c7d8b1f085 (commit)
       via  36d675fd95dec21602e7b75c4eca3c282b626a29 (commit)
       via  d8ee6b767476250249522dfa3a746602841af28c (commit)
       via  a7239526f15989df87dd3a1b86ace42c36254e18 (commit)
       via  4878bd1666badf844156b6f983759e4aebb047d0 (commit)
       via  8d31b971122585f477062dbd4d317125acf58945 (commit)
       via  5c2b2351e6d1b9be40b3ac232bcb20fac5eadf69 (commit)
       via  23b132e4a7c0eb42bd3ca94a2b0efd92fc6d5979 (commit)
       via  22b032250265857d0e6e1f90ebb6db0124180cbf (commit)
       via  8797b3632854703d65010764821a7a81c8d4ca24 (commit)
       via  f2b9aa57779dbb70b25f2541216d25ae0b24cd3b (commit)
       via  4ac8fceb9b3f4fa2453d4a77a3f66de6a6f9bd69 (commit)
       via  489a4b8d3930eeb9afb129b4dcda544efcafa4b3 (commit)
       via  74d5c10c17eacbfd2f70ac5b8e9f73592040ded2 (commit)
       via  0202adc6b67cf74575d090be9c94f4111aaf6798 (commit)
       via  1f2f140ea03fcbc561200aa2808f6a120758eee6 (commit)
       via  0777d9397fb52f2c98b197339865179d326d47ef (commit)
       via  5a8b995a509acaaacdc33b72149b556d97bfc53a (commit)
       via  b5bdb101548ea334b0969a5d35f9fbd39d438d21 (commit)
       via  e5531044a9c33ea129ce222be7c0cbe186a8db6d (commit)
       via  8904556565ffebd707e140fc95b53899ac026a38 (commit)
       via  f5ab391dc686a27a3d6f070657d7279001c5d5d4 (commit)
       via  4040ae07e002b8457a49f1db108084aa012a1503 (commit)
       via  8513a7e38d7bf3538d235668ec16081cbd561460 (commit)
       via  6525366e5557c7a53197856dd568063a2a1bba6c (commit)
       via  a98e56fbab64dc5c35f568420672c8f2e490551d (commit)
       via  aeda94490cfc4eb0063585253f707d4042d60ba6 (commit)
       via  88718f04077c88362a2a690e1e32fdb11e522e8f (commit)
       via  77f761c9b1db777529656bd3f512ebe1a04b29ac (commit)
       via  002c8b5728625454c4f271695db21a1f6239b6bd (commit)
       via  eef37baf475fa8311176ff80220c5f7c0a502c13 (commit)
       via  b8bbe207d2f426fbd9e034c1f65cc45bc6af7ec3 (commit)
       via  f9664738bc043b20c27b9e7d6560759233d96522 (commit)
       via  e9b77128b33d0403e09ffd278447e483ce9b125f (commit)
       via  f72863163f32877d837dcacf1f3a9ce106af6493 (commit)
       via  7031812ba83c01246205b30a11fc79e99a0a41ea (commit)
       via  4fe753df26e46c55e65cebd82563eaa21b58ded7 (commit)
       via  6da6686de57c149edcdd86c85dc95d3ca8e88a1f (commit)
       via  dac0a43c5314b510f1b281dc910ebc33500902ac (commit)
       via  56bffcdb508f932924a25bffc20f4736c52ef1ec (commit)
       via  db9ab33947c409b4ab88570e95ceca0985cc69fb (commit)
       via  f63c6546ddbf1e7711b540c96f0c9adb8615e449 (commit)
       via  f32de3dc93741ac13aed564aa1d0fe98baf6e57d (commit)
       via  14e94a46039336952def0b7ea7cee01a588938dc (commit)
       via  29a0539625ff000d8594b4d20959d9cb806583e7 (commit)
       via  e0f566b2eab3dd39489f9a73c1cf812db52f9b87 (commit)
       via  f8cb9c52614e0a8e477f1ac557585ed950246c9b (commit)
       via  ffd6783e8a242e8bb29d18394cde3b0dd419d5a7 (commit)
       via  620610cdc7b199c10e6da049672f19879d22f247 (commit)
       via  39f1f287fa9f9331f3a4ae580c7d7dc716aad035 (commit)
       via  cf885f0eb3bfd8eda973aa4b5e89ec3bb235b01c (commit)
       via  559f84b002d0ee1d16102c063b408e9b0eb66d8e (commit)
       via  95ed2b816d37c6b204df32316f2a0e998bc7b7a8 (commit)
       via  3ee849316253121ec4ee51268bc814ab60d63b2f (commit)
       via  89b9afe67bcada229e8023ccde3846b68a4999da (commit)
       via  4569194b089f11d3ae76b384752c65c2c8be6037 (commit)
       via  a31f0a888d305a221f9262252e824adba5bddbc0 (commit)
       via  5c6135d76d3ea8daa6da4b3792ab542ab9827212 (commit)
       via  858b079d3ee5bf8ab7623b817f73cf958e684e02 (commit)
       via  d27c8afd4a3fd27fa1eea037f61b5c74bba8ddb1 (commit)
       via  e45e9c8ee2c9d9b496acb3bc0ecac02381b4cc4d (commit)
       via  cd50c7b7303886b71fc6fcca3526d896784e4bf6 (commit)
       via  e67ed6620ca2944d75e0ec66219e663171877d1b (commit)
       via  81eaac3d482d20e154b5e76d714107a176c40018 (commit)
       via  30b33129c0fd84fd689d6df70d1062f5295d93c7 (commit)
       via  3dfcca0eda08ea6be763876de4b20714e8cafcec (commit)
       via  646087a498bb89037ab2d09efab9fbc3c5c0d326 (commit)
       via  5d49f01e2334ac7fcd2ca832a6eaa428b460018d (commit)
       via  be9054d5b87b0d702a43a459c804cd38020924bd (commit)
       via  d75365c1f9e423a7312c8997bc2aba613cdd58df (commit)
       via  70b6756438d0ae0b14b015a78dc5aa30eab0c363 (commit)
       via  441da8ce869350162233f5e99b2171eacf403e6c (commit)
       via  f22f4bbc9bbcd0545ac8fb81ce96f44b0579668e (commit)
       via  1b560c6182e181b61bd2dd7e7af5a2bc9c405b79 (commit)
       via  10f23bd10dc62e9c050a534d38367743d0db863c (commit)
       via  0141a2ffade47f43939e27a887306473dcce0c2a (commit)
       via  8eaaebcc6874e7f9388987413187df8e9af448d7 (commit)
       via  29ee42a4c72e1e9d66a061e0b67bdd25737660fe (commit)
       via  4c7276574080d9355eb1673c1e1e6bf787830726 (commit)
       via  501b39c4dd806c7215f28eb3a3d14b6ea98e989c (commit)
       via  84f4795fc93c7727e3a23eb9205750ca0f644fc2 (commit)
       via  ee845b34abc0d3c43491ac2e4f18bc02de5bdbe4 (commit)
       via  06b72725d2b3760edd7d2caae93367593b395253 (commit)
       via  14c6ea539b9ee7b98d0c6b870c23202798ba37b3 (commit)
       via  db22d53b4e2dc16de057d6bf423002299be1fc3b (commit)
       via  20995f67febf797469872fd95bb8f8f2ff03fd78 (commit)
       via  262bf9d41456ebd90f4e59c82feb24ef9a5f98cd (commit)
       via  71c60bb15cbe04a3a26c017bdb7d683623eda53e (commit)
       via  41f0eb9581c157a63abab6b83f968ffb689b2e62 (commit)
       via  deb1ab085cddd8b6de24e62f869297adca355cd4 (commit)
       via  eb482e23d37d37d6e81460c210caddd710c2216c (commit)
       via  534ed78109065890d8845f0b95b2af61cf24a5b3 (commit)
       via  75be74d7c8f6f4c138d609ad407c78fdf7a873d5 (commit)
       via  9645a253bc346740c94254f149fe66f3f39b55cf (commit)
       via  6c42988804788b1cbfd7b58ef8dc587ed67e4ee9 (commit)
       via  881c6cac96141eb4050efa969a2bd42c44f77aa2 (commit)
       via  fb26aa742850bc005f2cbacd5b53fb1e5a007dec (commit)
       via  078fbf31db64329fd22428e5c185cd6e4448383d (commit)
       via  d2e427207aefd210b5b16905ecb17fc77192f483 (commit)
       via  0f921694700e8e78feec16ca1c481e2afb26bfd5 (commit)
       via  a5f1895b069615093ca119114cf9257667497640 (commit)
       via  43687bd20dd04e502d170d9d679fe056bc353e89 (commit)
       via  d8fefe3ccf5c7a561b3b5a79fe6f535265d85751 (commit)
       via  b89e002187ce932e82394023820deb8407842291 (commit)
       via  33ff92c3d4c4066d284dc621b941c57281f8f3bd (commit)
       via  1081075d7f56a45b5dba99a760322c5dedfe7614 (commit)
       via  237b190fa1f01bf133d718d973dc64dccde7d89f (commit)
       via  72a85d0491630210c1416fe93f17faf62d3b0aa9 (commit)
       via  818c1f5103c9c0f080244840cf0043faf21f2219 (commit)
       via  0e04e15571619f29a6852c230b32e97eee2e9be8 (commit)
       via  81bcbf7df7077db27facf0470cf9e31c18b8333e (commit)
       via  5cb48ab03c2e746bb989ff36c05b176f528b5d82 (commit)
       via  865fc07b6991cc215e89d1ceaeb00257195a2aca (commit)
       via  4b305cac3aee3ba82520834f0bfe6e201b7462d8 (commit)
       via  e872ed279d1bb31b6770dd7fd00269c9d46a8e12 (commit)
       via  82e85aaac1c16ef44036d303f423cdbac16213e7 (commit)
       via  655cf1e26a4d6f4a44ee8e92f0d84ab7daca7a07 (commit)
       via  75a53f12935f136508af0b52c1c439a613f32c45 (commit)
       via  eb912a1e53e74209b16e3d8fffa6d346371929f3 (commit)
       via  7bc2aae4a3c4f6ebdb94e5dffc7298af7f29f08e (commit)
       via  3596d846e4a7996e95fc48d6d39f507cf8b6d6e0 (commit)
       via  2148c5afee6e8e2631ae0c826eeb9b04495959f7 (commit)
       via  8fd1f742cade458446cb197a256f9b117948550d (commit)
       via  b0a2970d51f85c5dc076bd22cb89eb06c01a36e3 (commit)
       via  3a7798fbe921b2eec3991ab113d4c2d3630afec5 (commit)
       via  7900cdaed05644be1bac7a0cf01ed767eaf8ee3b (commit)
       via  c619af744cfa60cd5b7db1b522cedd35d46dc91a (commit)
       via  8da9119fc555dac0be20b1f26b528e3dfa1e5695 (commit)
       via  51b5764a74fbd45c106c0abc9d072132a7c3ebfa (commit)
       via  010db1c60172ea6e62906ab4cb39c47508e2f629 (commit)
       via  c0669aea52898002f35560e689a07d58aee4f915 (commit)
       via  722b4b71b86862911e407ac69f68a50d9b9e436a (commit)
       via  4390cc2ef3e52f71fde252f73d8dc62daeb83f60 (commit)
       via  4c8dbe2568fdb9039ef81665ff6c1a490b9c655f (commit)
       via  ae51a782544fbaa9e67ebc5056c0d93cd3121168 (commit)
       via  e5925a9de31ff070b8f7b2781d0e75f8c8b37258 (commit)
       via  b948e95ad982fe5bb17ce671f2566dcc1e22212a (commit)
       via  a7ec985d7f592ff0010908d5b6957e0d345577a3 (commit)
       via  8aea7fb84b49983f1d544c1d1d6134f7ed930bab (commit)
       via  7b31606884c0de70d07920ae5f2c3e93f7e5d5ff (commit)
       via  4a77ef03f76b169dabb6040cb0a20a5159e00f8c (commit)
       via  f4e1aa871bfe35983a989734804251d551785e59 (commit)
       via  be618dad3b73a64a70e89a27ca731d2466d7fbce (commit)
       via  b5d4b0324f56754fc340d08681ee1b9e176af98b (commit)
       via  c05e318d03308fa8eb7dbfa83533d342ad1530bd (commit)
       via  5614c2ed8f64d646a250d553b016db2f220cc38e (commit)
       via  1dbf7cec84b5b36cbf7d6477bb87301dd6667722 (commit)
       via  db942589fa0b8c864355f8667858d954bd878037 (commit)
       via  281c68476aa3382b8ed964c1839c1b51184ea6db (commit)
       via  958c32f5b53d5dad610da7fdb6511c7b78422699 (commit)
       via  416c9e42a06cbfaf098d97446cf75321aff3aba2 (commit)
       via  aafc6ffbebec389052ec540aa3d6620772719cf1 (commit)
       via  2a1518b5b2cca67cbe139a98a1c26b39f7c6a1cc (commit)
       via  e38e648f87ef071ee34e65cb0a3b065bf4b1be1d (commit)
       via  83be921a9b84a8f34e6fe90d444557c86f7823e3 (commit)
       via  65797fafd745160b62b64ac2dbbec8c0516efc4e (commit)
       via  6d1d92d7802f5908ae3cb0bd85942215de87f060 (commit)
       via  3f4271f084959bb825754600441fee1bac677268 (commit)
       via  39dd8a3a967ee9ea2188a36115b22ad052e97321 (commit)
       via  07050bcc310ddf7c85fc63b751c0a4a07c7e236d (commit)
       via  579e270cf98d4cbd6a37f5469274143e73acea90 (commit)
       via  f687d8cc0b507c1553d215bb7ae7d7185ca127f8 (commit)
       via  5703337fca7018662b5df528c492bd76392fa363 (commit)
       via  8bb36ac818bac352b19761698a670a3dbe551e44 (commit)
       via  5b957dde1236b05e3db9956310b08152892f52b8 (commit)
       via  89203e8ed0f4b57c45035dbb6ab9c1c54e732841 (commit)
       via  66c326b6fef15a3cb17ce1290bcf39bd0a8dd1fc (commit)
       via  be2305f545f64d0a3c0e5e71876c7b36b935787c (commit)
       via  b5bbce12dc2dfdc3bcfee13e702b9d99f113b84e (commit)
       via  763cb60f33390b1c6f9f09c9186872d7b1906172 (commit)
       via  cb7a69f255775ff04c7ae3dd7cf0ad6139c09233 (commit)
       via  fbee9504c5407f4a9f3cf6e85cc8d0655a34f0d8 (commit)
       via  799d213bd16d088c3234c7649ce84d8756e14bc7 (commit)
       via  024117368853ea06607cbbc0c9245d18aabf9e20 (commit)
       via  fcc5c9eac128c78bb87a4fb84f49cca99305dbf6 (commit)
       via  6b8d5347a4f6230c4d907bd585b1f7f2d29771fc (commit)
       via  fc58f2cd0c67771d31aa7fb3338137e82d5067ae (commit)
       via  a4875a92e8066b76cf6c3f2b2214af86b01b2764 (commit)
       via  5599c1b25e196e53a79dc1c5a48eadf06a4babb5 (commit)
       via  fed3408332db3915a943c157e5e37fd9e54a43d0 (commit)
       via  e65d0e9fa52234351373c894a86ac0cb6e921ded (commit)
       via  60b977edee66beb23feac8bec0fda143c3c0e77e (commit)
       via  c859f29a9d7a993a417552f58dec236f73f6fea2 (commit)
       via  810517800ae5d78c9c76f7d5e04f15ba2cdc975b (commit)
       via  45245a4699b527e06e36e9b21c2234d458d9461b (commit)
       via  9d8794aa2315025950f479f71501de6c3b2e06fd (commit)
       via  4d81f4f693d74d0f5dc3375f12871701a8c1f2f7 (commit)
       via  59697b40cb9d1d76bedabd89411dcc1192c967c2 (commit)
       via  32a113aa8971e93a382a7dfb1b069232238c18cf (commit)
       via  3044b77c782671b6ae83d8a3cd8ef37f8b038033 (commit)
       via  1e9af9a3d2c5af0cd64d938cae02e77f651254df (commit)
       via  c4c42be1f162893932038a2b6fad56888bf255ab (commit)
       via  80a8d7476ed19e38439561f7975aa8e6e33eab91 (commit)
       via  323ab3d99f0ceaad21c5903c17dbaebc501a80b8 (commit)
       via  522da2cde4a89b558abe92121f75027891ce9c64 (commit)
       via  e3cd80fd2bc73ba0684703a25d109c6dbf50e524 (commit)
       via  1a6a981dc70cc45635e7c6c7a9df0dc916c533d7 (commit)
       via  e779315ccdfadb24f7749c51a530dd178998a3b1 (commit)
       via  2fde2efff5dfd2d52b76dede7e73c3ecf9286c13 (commit)
       via  8a624fa926658e86d6b8bc8e10b8abc18b387923 (commit)
       via  2555c962ccdca0341600013a97de1aa25d6ea390 (commit)
       via  d8af108f5766b778f024702af01dfc30f3453080 (commit)
       via  8806e482a3fd1762000e9702e00ce9f3f70767d0 (commit)
       via  1ddd03c29b469ae525c7783168c082099684f2a3 (commit)
       via  c47c034230639afd5abf8ba22e696be9aeaf0387 (commit)
       via  ba301c31868bcf8ac0ce43feb0e83944cd91971f (commit)
       via  93480bf9fe6cd4ab2983854b448dafc1a1034eb3 (commit)
       via  0731bb3b41531a64ab2ce7c37c20471d231d3219 (commit)
       via  31f297213970e0edf2ec30442ef812ae02527a7b (commit)
       via  3c84dbd55d38c1a2aa53db354047ec73b9ede3d0 (commit)
       via  a365a334fff47210aec9544f56734022316d6656 (commit)
       via  d566eb777d6c0cd7dc09edc0b736dbe668668a2b (commit)
       via  958953e814d802c998186f3e3535eab7a65bdd65 (commit)
       via  933142ff5838718f683e6855ed0a7e7f82c1d3a1 (commit)
       via  f3ea216b69d0dc583b63b7a854155caa739a2aaf (commit)
       via  5980a3cafe18061365b92222282ead155a639b67 (commit)
       via  b548323ad63f9ba192433866bb5e1ce8145a7174 (commit)
       via  1d2aed3624fc3125f59d0dc0ec6aec531533574b (commit)
       via  ee88fdc026b0c558934b57c029f46a009b066cf1 (commit)
       via  3e79a006b3a315096bd09a95b53a625add9662ae (commit)
       via  9a773dfe4bfa970a0734b47eaf6a4394559a6571 (commit)
       via  1f2ecc016c9cde8e26c6c550c950263d33a859bc (commit)
       via  18d77895b945481a4b2354b9f3d445cf33a38844 (commit)
       via  1591d685c36a8bba463b8846323ef5cc3d71fd99 (commit)
       via  737760e7a910e814759cd79b01bb3eddc86c010b (commit)
       via  cd7950c7720d2f631741e543e24f1ed9cf4e3883 (commit)
       via  4c008b1987aa53769899e24808b6d74b41b4ff40 (commit)
       via  a1a452af1889235a9ec3cef2cbdd3f67fe70f2ef (commit)
       via  4572c4be9dcb5c4fcac7426d4954d4451223851c (commit)
       via  029dd7e006c850883026be022ce09c7e0ac60d57 (commit)
       via  c42b4f34fec4e69e632dfbea2e98968b1eda020f (commit)
       via  5412c73802de5548274548740575e5b8b6a3a387 (commit)
       via  977d8f92732ce3642e122d3a6c2956339b65bc10 (commit)
       via  9a266d91c0cc15f10ec03c4ebb51e13952556384 (commit)
       via  d2299029927cce69eb9c4faa0a88f99ed3e45997 (commit)
       via  b748c263360ce25d6ccd56945ff1aaa225534ddc (commit)
       via  510650bb774f1880cb351a12d2b2d09b729cc220 (commit)
       via  1758a550cb6fe57636c078894601281a5c72b1be (commit)
       via  04fbc13b5be66bf9876560e3be33dfd486e9fa56 (commit)
       via  5d5a7cce62d847798d407771ae84f63e1a0bd0c1 (commit)
       via  5805a68e0d32eae42cc5be4e5c3fbe82f3fe059a (commit)
       via  b41a8289a5d8977c41754f1b5ca548a2bdae35e2 (commit)
       via  61988bf4eac9cc885283df58b2887e06ce07b43a (commit)
       via  83ba8527b39f8ced37843d46336568bf458fd55c (commit)
       via  580ad93e26221610e2b871bca1bd6fdd6e87ec2e (commit)
       via  504e1e38a8724fc2439f405f0aa8274b58db7b1b (commit)
       via  0e0362b2da54bb5055d61239c4e94366b85c6cf2 (commit)
       via  244d4b3d16487f0f6bf1235b343ff4483c0e2983 (commit)
       via  080ddacee96436ce274b98da328c1162bf162f71 (commit)
       via  62453f213850685954cac61d9a3f50091ef02d50 (commit)
       via  c115eb9f3cfcda9d433d13b03ee0dc04278ad405 (commit)
       via  f19ecbcededf1f6d371ff32b938ed1c70dc72421 (commit)
       via  3900a8c97649c512b2b7e63b86406f6ed3bf4ee9 (commit)
       via  a9c8f484e47d2729cea902777cc146c2f3d54697 (commit)
       via  042838fb0ba16758f60a164048c0b792b3ec3ecd (commit)
       via  7e25b68323adcb46bc43d79924d2008386e5fd0d (commit)
       via  4061f7601a5ef0329ce5d315f78e077073f0d6c4 (commit)
       via  ac9a3bf083cd7af1077463b4ba5c744aa7b98a0f (commit)
       via  64cf1a9534f7e762c5e7a19d87fde4ae17708dcb (commit)
       via  7d80915b235961fdf9a9c4b2e0173aa02cc0f193 (commit)
       via  cdedac13f206e7a12ef3dce36b4bf6307609e306 (commit)
       via  a6958aaa7ea3f6d94651ccfe1c4710b05ee19e1f (commit)
       via  b38b24573b8903f643467152ad030ecc1e3d274f (commit)
       via  2c204efae48ffb866fe0cfb050c19608261efa6b (commit)
       via  db880ac4db091bfa45fa992c74af6e44f697cd83 (commit)
       via  5b766ed6fd77e9390a82aee48fa34ec3b1da34cf (commit)
       via  f33709e9e6ca4a6d7ff21ac5abc2917952c17c71 (commit)
       via  d2dc9c5d23f2ba79eefdc00b3a87213ac9740e65 (commit)
       via  e05e70dbd49c4b84c953ccd7dac75718bd051831 (commit)
       via  fde6c898c36dfe00fb1492252b44ce253a569ce3 (commit)
       via  566680938513f520ec012df5de43e286fe96fd73 (commit)
       via  59cf3ac5065a6ea94eda09207f99488c02963633 (commit)
       via  c8e7fb7cc31ee154b3b381778604ba8e5a0ecce3 (commit)
       via  266849caaa473d56ac737ec6dffc260eb41eee72 (commit)
       via  7675045cf3f1a995f195ad48937c94241f7d00ff (commit)
       via  0b06b86d1f153131e1b811eaa784d4fb101096d7 (commit)
       via  b4270ded088fef88371904f02a55842fc62363f2 (commit)
       via  58c1401b287df2f6985926fbaa27e2d56bcd97ec (commit)
       via  bdf683ec35278f04a8a71bfc27ed8a18dcaabb25 (commit)
       via  14a0d566c6bb909e0b191aec60da61cdb0bb6878 (commit)
       via  b4b2a5377e92742fc3bc7b748ded86f46f1d62df (commit)
       via  e8fd539ec863e217f0505f81dabbd73cf67b55a9 (commit)
       via  2d489a8dcd54fd6adfd97d1ea0fd6160768d7a27 (commit)
       via  af89112d78fa3cf0d805a5b2c47e040585f1d838 (commit)
       via  1365480ba076593ea45e1a50c74d1af0fec16f3e (commit)
       via  9c72a4fce3667cb450bfb8f04ab20792547079de (commit)
       via  27df14a96e460967e4ad6fa3e2147dd97a4959ea (commit)
       via  4631aa18f5f25e1f0e48b29b0233482fa98d70b7 (commit)
       via  4e7b3ab614d18fdbf3d95afcf5e3a982c0bb0d49 (commit)
       via  a335f6c7165063ac6064bb077052d4b4dacf82be (commit)
       via  f29d5bef763ebf32ba2199f28c36bfd5234e59a9 (commit)
       via  534bbdeaf4261b5891f5d45426670dbc5738fbff (commit)
       via  340a43798f31661c55325d5a87f075b397388554 (commit)
       via  d1b583d874f5060028fe33b190608d54e1627d43 (commit)
       via  31eacc5936c63143c6da8e438bd01a8f95cab377 (commit)
       via  0503aa21b23a2e661a928f114a3eb1c69db9d702 (commit)
       via  33e00976eed180769a3c2e83fdd5350cc607939f (commit)
       via  dbe92240b61ac62b722c57e27ca23c107666920d (commit)
       via  197aaeda8ba0a4e7de0c47487f112869d0195d8e (commit)
       via  0273b2fa9433cb0d8b8305bef23540c59fe0062e (commit)
       via  716baba1ab1e40b64bd9fada180d408f3216f013 (commit)
       via  43a6f280e8463e59af8e86d5939490db7d51b6a2 (commit)
       via  53291f6ea986b0e7096b34d77656930298c124d9 (commit)
       via  9c4a393d7ad42f9ad6bbd11744fba2e160b669a5 (commit)
       via  d2c2fc53aa11582b9e2be2b6473e16f1b833a6a9 (commit)
       via  be9cba7abc177bf408ee43de8196feefa526146b (commit)
       via  b85545886540514bbce23273bbc79fdb509fdc96 (commit)
       via  7816cead2cbaeabce322c486200a855125ef7e4c (commit)
       via  3433074b6a753b0cbe5aad25948df4f05765162f (commit)
       via  e9c89e347848cb583b29e0ad063c448dbf5c1906 (commit)
       via  813897e3eebd61998c914deade71cecbaacd7aa0 (commit)
       via  fccfb9ee2af9f1ef3b3ec4656895d0ac6a0086ff (commit)
       via  ed8c0e9f0d681db1f1f25e30e78291ad222588f2 (commit)
       via  09da94d541aae7c6d1d339f9ada9dce3061f4d34 (commit)
       via  ffedb5c68cd78a405d72feb25bd31153487023e8 (commit)
       via  5ebd16165ac31ffa6d5923f053e483d9380d3441 (commit)
       via  70c799c8325115b4df7cd2de23d5ad6ff768f6d5 (commit)
       via  16d56833df80ce6656761541e9ca1ad67c5f3375 (commit)
       via  ad584d8383ca2447451c4105b31b96f31ef60b81 (commit)
       via  bfbd616a226412c43c5a5d82a4f418157c16b560 (commit)
       via  62c84fb393697087cd59d064b4db114c4553b390 (commit)
       via  2c3d17bf271873d91047d858eca5d321fa3cbd84 (commit)
       via  5ecae750b48d7ee7ad2207bd503e43b8b8160aee (commit)
       via  393dbd781b3f0dcb4ac90cfde1ba8e3d734d8d41 (commit)
       via  444c1b0ed0731910c08fd3708415a5300b38e39b (commit)
       via  a8ce5598c5067f19f2cba9cac77d5d6390c7f1fe (commit)
       via  025de12a634e0430d0ff21a6c33a42ba58abaef0 (commit)
       via  320db73bb97dd7e0bb3f50a1ac9273d18eea01a4 (commit)
       via  e1bee6aca61e5501bc46653d9ca7ba98efbad980 (commit)
       via  1f8413fb30d6c429d283c20f232c0ed73e12a542 (commit)
       via  c98ad94fea089a3a0a0dd339752dd817a63c545f (commit)
       via  0897957beade15f9224066c015da1b9a2dbb1fb9 (commit)
       via  3ec9528c6c8fe05f4d2bfe9522a513f1b5865596 (commit)
       via  bb7820c65daaae6ec260f6f6b884f0d4dc5fd98f (commit)
       via  7d0348f081468e6af68879721190da7996e09c6e (commit)
       via  7623164a088658b1546d94f2574973986b13f540 (commit)
       via  702d282b579924d5d5a250f019fc2cce01ebca05 (commit)
       via  b57699722f35f8bdedc63e634a4a72e5da87a4e9 (commit)
       via  74a91351d1f4f68526bfdb40fb0f34d4fd12e7bf (commit)
       via  37b481e4a33732d84388f16bbe64e2d795cbf960 (commit)
       via  c7f4d2c4dc5afeb5554832c415c0cfd5b84377c4 (commit)
       via  ccf74d286a90f636ce9433bc1aedeb3f07cac0e9 (commit)
       via  c46609c148ea78f11e4ae68feacc8dc157dabe74 (commit)
       via  6eb6d992deb91e0cd73bfe7ab374d2720d224891 (commit)
       via  bca81b6e9bc4299be94bc1009fb495ec0b09bdad (commit)
       via  5e1094e513013b534777c65ac4b08049c63ee45a (commit)
       via  ad93c34c1efd0217e502a7491e1f8c4a01c33d16 (commit)
       via  a9e79afce7316e195df9c47781515650dfe80651 (commit)
       via  ef54e782c09969b7839d06f99274c5dd74828ae5 (commit)
       via  1c093534670e89d8e6487e9c63c0199e47311a6f (commit)
       via  4eaefad860ee6596eadeb817d8a962e2926d3649 (commit)
       via  c8a76fb8777b8007e35bf34c23af95234387fd7e (commit)
       via  719d497f91e21d5bd80b120474b923751a55e4e3 (commit)
       via  3c15500bb84dcc5a31814b7f53757b461b583280 (commit)
       via  688ed47c27ab0973ac6adb255c10595676775963 (commit)
       via  a9ff661cd98bb7523bc04ca88270d64ef1d00620 (commit)
       via  5cd3b546f0827223b76cdf9c7ac99ca75a812d1d (commit)
       via  887ed13ccbb86dbc66e2f38e2db965f486b00038 (commit)
       via  f1397b34b87b118a76ebbe90bb7e55ef8cdc72d7 (commit)
       via  a1688feb3e3b6c721a17c2f0d406a0a0285b1cb4 (commit)
       via  8fd6d6703940898a426adfc8691dc392c462036f (commit)
       via  100ee8e1bb54cbb89eac435906acaa4f857dcf22 (commit)
       via  e2f8fc6b7535f998731e1ec7f6020a782e92aaa7 (commit)
       via  1ef1ebea151f80a8ca32f8136f3edac032f694ab (commit)
       via  db486b73c0af8becd41ccf83d7390e8e4a03d77a (commit)
       via  66eaec1c0e9a05ce9bb56ddfbd0501d66c669fe3 (commit)
       via  1c956a9150228986198d6f2a92381f8816a40df9 (commit)
       via  b300b57228d9b5098b34b14a657e8b0fb8abceb4 (commit)
       via  90c6f5fba1e1841cc93941cc2dbf6648675f7204 (commit)
       via  88e1c8c75f8b6cd1249934cd5ad91565798fb2e8 (commit)
       via  1f9bc1a93e85eb70c46136888d7e30ac1204f71f (commit)
       via  fce2bb756a266873cf3b35feaa74c9a8e73bef58 (commit)
       via  3e8092ec1be7df0a990be78bee4a93581b0cc5ae (commit)
       via  174c51d030e15406f7fbac49df4fede7a199597c (commit)
       via  5b1bfa269153faf48446e2f57fc5e55fb628a4c5 (commit)
       via  6753f5ac403d5f1e5f042e5a2be63052e613b3ae (commit)
       via  6a084ba247eb59e2f5e0cdbcc379a0064d29f9f3 (commit)
       via  09a9e5e94c7175535e525d9f0645b1e4fc7bd404 (commit)
       via  c783bd4bbcd97e1edfdd3765396e433c1b7a3804 (commit)
       via  c06137d59c5908fa0f7ca148c70e73c89833907f (commit)
       via  86589743a25e8bf084e6e6893517a3ecee993450 (commit)
       via  b5623fd111963fbdf5246b9327c03ec6f364c246 (commit)
       via  d6e9f343c9615aae2049acc162451fe0c8a3f89e (commit)
       via  9e8d316f98ee52d9a982dcda22d46a5d4e24bede (commit)
       via  12f33f359cd4469dddfa454fe47715190dc025e3 (commit)
       via  8a0076a7640db8ca488a8f300c1c46cda397761e (commit)
       via  6e2677e9891d56ca9c64048dc4302b117ab32c86 (commit)
       via  bcafe8294b55e3e17bbd99381b395ddc37e1e838 (commit)
       via  40a5bf1b51b8b0508902db515e2683016f3bb075 (commit)
       via  2e96b3cd99d263a23c8f3524b11bfcc2f6f889cc (commit)
       via  7803688b40e32bcd176000a5f011bf0e2aabda85 (commit)
       via  f4597a051d823346f67f30e06910efea530aacf0 (commit)
       via  7eda082b652be8c525192257c1912626b2ac7eae (commit)
       via  8a3d6f5378500bb394d0e555bc1473ea6279f0d1 (commit)
       via  625d37928c3a68c27a7b0b2cbd2d8abb099f3cc9 (commit)
       via  550693de5410011d79555f04092e481710cf204b (commit)
       via  41021bd85a4c40fe293ceb8fa16aac954b4f3df4 (commit)
       via  1303babda4c95f1ff1a39b8908f33c69cf500b0d (commit)
       via  81e003ac96aa48f1efe77f4b9d415790902ac5b6 (commit)
       via  e15463d4c9fd3b8ea4e7487bb617c713f698e44d (commit)
       via  86ef0c89c7c97df887a83303f76cd6113e6d8889 (commit)
       via  772def80337ba1bf30028216214014454a2d43c0 (commit)
       via  cfb3cdf1ef3868f3cc2d57094ae55bc24dbd5fc3 (commit)
       via  23f5fa60af7dc8dfdaccecfd663833cfacab1101 (commit)
       via  b38c19ed6013b4418a5751d0de0670c8716a345e (commit)
       via  8c7bd5a874a26c733f922181b22918f4a80dc594 (commit)
       via  655ad4a630189a4b827863811fad5155dfe8f5ee (commit)
       via  c2c99814f5f965491f4e24b5a345c364b601ba2b (commit)
       via  ae515432ca997c69911123c12c4c4051b30d5107 (commit)
       via  1ba2939770a269dfb9a96daa3a67f4c204ffa4ef (commit)
       via  ce605762cfd014d0379cc5766a610082abb93374 (commit)
       via  f68469bdf2908165a6276b3c0ea9b8286e8bbade (commit)
       via  454b7560636b6a483cd7a3e4a4c0c293f250df29 (commit)
       via  85772e3fb3c79dc5fd6ce0f407a5fcb04f7d49bb (commit)
       via  4102c5682b633a6d5b58a4c26e5822378107766e (commit)
       via  316e0759a416de2f2cbb234da54a3a0d74abc37d (commit)
       via  6958f53f4a1ee5133fb200fd003596341b6bf207 (commit)
       via  5e9e631345fbb1a567c46f71b68bca981ff3b2d3 (commit)
       via  e950f4a0bc51f6e79c5f1bc101949a3d3bc326bb (commit)
       via  4778b48f9148c8679c67b57e10125a4e37d12447 (commit)
       via  39db69eec92d5d39c6ba0d04223dd8d18bef339d (commit)
       via  1be1a83342d1e5f9f474f2f4ca76cf1caff8650a (commit)
       via  bd88a5665cb419ef49a8a72ba678be097f0da293 (commit)
       via  42045e902df52fefaa88aa546f612eee55c7656b (commit)
       via  d197cac21bc04c13da30261c907ea9213fb5db17 (commit)
       via  dabef35f1a0b6718c1a717ed31d6663bca76268b (commit)
       via  35db46a5c28c0160e3c681b98ef7033e48da85b8 (commit)
       via  cc9b329bf08a525010a13de730b9fca09aad4c85 (commit)
       via  d77e9efb89c9d721770f6edd87cbc9166ff10a79 (commit)
       via  660deb62e82e1e2e425054ac67835aa63f4773f8 (commit)
       via  22c95e4ed0106625fdc357b454c4b8ea111b58b9 (commit)
       via  84978588c7d21b3699cc8d22ceb080f0d650520f (commit)
       via  2a560d880071eaf58a4bf299105ebb817da3fc90 (commit)
       via  dc30c57729a95d3d63fa45fa3ddad6275feb3dd3 (commit)
       via  a301f3fe738ab729d9a0188e9a82c2fbe409dc96 (commit)
       via  4b37646e41b1b0200a34511c93e05f354cdbff54 (commit)
       via  4804cff20260e0fe5bf39b1659522be88719fa8a (commit)
       via  1ecb278a72c158eda363c61e650a7b12e8a9b653 (commit)
       via  e62f418b1b7147ca9034cf6d7b1eec1e7f3ed45d (commit)
       via  9eb632cf7973e5d22a5c4d1643935190658d888d (commit)
       via  e3c8aff2664511308b8bf47206bc650b7dfef590 (commit)
       via  75aecddbcccc9baa80b83838936c07ba192b962c (commit)
       via  237a5de8e9414a300950a2dc4f3a21541ec1818f (commit)
       via  353a253053057cf04c6a26ab81d3392bc49fefd0 (commit)
       via  3ad7a03987c6a8ad1e967f60a4f220c5fcf0842c (commit)
       via  0f3365f747b624641a00250d22b5a9046b9a8fd2 (commit)
       via  14e67f54390d0ac544ac5358acc2ccc199ae4aa6 (commit)
       via  0fc7fce20043125765cfcf4100e5017a56f410f5 (commit)
       via  b874bf4e5ad31c06dc328f828c4126dc2d674a1d (commit)
       via  36b220d28f195cd650063a52bd0a78e0351649f9 (commit)
       via  05a0fb7edcde344216b104edd8b91e80b15fc3a4 (commit)
       via  cdd3c94f88d9bee4fb730817992def8106396ee6 (commit)
       via  7e07083ed47e3476e2c67b5574e50c41bd5b64a0 (commit)
       via  42276059947706958938756fd56106fea9cc7bc0 (commit)
       via  2ef2b38f4dbb3e4012efcfc48fb8eb81aa189704 (commit)
       via  f9cf2429b1fe0a38bd806c95de359141ab7ec61c (commit)
       via  40d9be8f0fad65f652c81df5ca68b2c983fd5c5d (commit)
       via  4db4074fed6147c2f26c6f08cb38d7ba4523ac30 (commit)
       via  cc5ddfee8b7694743e5404b4e4475e11203ed693 (commit)
       via  3b3c1c8b67edc16ac766a7bda8f865cffddca520 (commit)
       via  ee3e3559d03a59087cd2122d7e702c8c81a9d37d (commit)
       via  dc0767c23c6a6bcbc85bc4bc935173fbf6efb147 (commit)
       via  2e592bc1fb9401d2fa55aad544d3484a56c4fb58 (commit)
       via  79bad0a7b040a491206167e2642f639f6a1279c3 (commit)
       via  c5831bbdf54d5b29c8401ce236e9ae894c679832 (commit)
       via  095e65ec95b69d6b2514632eae5267b33fccde3c (commit)
       via  5c5a414d5e4e5b031fea2aea8376ed9a0871e652 (commit)
       via  7f178bf45b1d7e55e4f6c1cced2eee6611968795 (commit)
       via  9941a6143b36ae4ed1cd2f834f38e8804d8e3924 (commit)
       via  73bba83a7538eea674c3900e193686794786c14b (commit)
       via  7cf2b810fe7de1d96a15dabce37fbca3219db033 (commit)
       via  954c5dbd0f3430121338c811e91bac45021f9740 (commit)
       via  41a9ec5330168bbbba749a1d66f7bb57276355d2 (commit)
       via  66139ffae5f96edc58b630b63aa371368862f849 (commit)
       via  7e59a2c629b49807093a579f52aa18dc0eb81f9a (commit)
       via  12747c2d9293eac46a39696aba5440aa016da19c (commit)
       via  5dacf96e7813ae83a1f26b388f95bad90007c140 (commit)
       via  d775bec0e41cbfa689c0387ef92c19de789acaa2 (commit)
       via  dce5d07fde2566c416de11140f6795b444aab474 (commit)
       via  ab12843ea64fbaba50aed73e89071edf33ff9479 (commit)
       via  38d4937b7e204a5f145dfa2316b7029d06c4cb42 (commit)
       via  295bd46a138a3d4bb7b5bf134ebeb3af1dd449e3 (commit)
       via  8be228775655eb55d3615dd29c0b12121fba95bc (commit)
       via  68a7c1cd60deb3223a5222bfbfe71fb11ad28bdd (commit)
       via  534910abc712d2120b75072eda85dc43d53c496b (commit)
       via  ba8b610f13ecfe6c01508d9f25572456db4d4673 (commit)
       via  fd5498ff474a2be4db134b6f10eda548b8c106d9 (commit)
       via  d64a2df3d02b01fb896ea6f08880360e9066dfbc (commit)
       via  4a89fd9f634f98ab9bf1a5db43f82b1bc024bea7 (commit)
       via  aa22df54583fd7deeee3f8f9c30f372f0f7aadbf (commit)
       via  df99fe1f5df6fe3ec101762c3a2d1c58b2cc483f (commit)
       via  2e09da12de8c33bab2c5e6fed2324ada9e9defba (commit)
       via  7a716ec39af55947d4c9c75ee779ff26f81174cd (commit)
       via  9b5f290c71ce25eb9f7566bf119446926da9e971 (commit)
       via  7df0028f2a3a291241c31a2ecd76b5546e392d4a (commit)
       via  b5678a91d0eb5bfc3bf68fd812cdb15da551d55d (commit)
       via  986e9ebe95cdf835382db3810fe33ab4f0e90e72 (commit)
       via  69e0d4792487178c0dc4468890c3b20fae882810 (commit)
       via  79474c4c861924f0be700ab9380c0e68933d6738 (commit)
       via  de1eb5f4bc31eda9c31f18acde32c7b010d0c864 (commit)
       via  411b188c98e6fc38ea83fd281fc9575ab1f7fde3 (commit)
       via  7827e741157314d572ce465c44f9b565bf5e5c32 (commit)
       via  83bb8625c67026b51fe45d2a04a1e24eb15ecdce (commit)
       via  f6d1f9d7c6656c8fce831f15d7195e22170ca3ca (commit)
       via  0f937335777b2e97ddf03439ce2479ae26056966 (commit)
       via  1a8b44dd46197c7e760a61eafe19389e42ebd281 (commit)
       via  09b998e2ad926852eee3a3d74f9d539a67555dba (commit)
       via  c68ab6ab1894e06033c13f83c3ec1fadc10ebb8a (commit)
       via  a7446d64a2e68ef1142a15cc38eef437118dfd1e (commit)
       via  90b8b657ea6de6b97346a481c73291a2ff35a319 (commit)
       via  2924aac3a39cac1180da11a39b7bc2a1c51d7641 (commit)
       via  270a74d6ea95d93e4f993982fc935638c4abd321 (commit)
       via  227a3608cd89eefcb79453ffc646027bcbe791bd (commit)
       via  cd06e4e6ebb60ac29cb90aaa31df89ba05d9a288 (commit)
       via  6639c3606a6e420060601d94df30735925a6b596 (commit)
       via  5afeb651e12b02a25139901008e943c012d083ec (commit)
       via  2bb69bee23fa9613bcb9adcaf8b568f3d60dccc4 (commit)
       via  05b7ddb890da9f0fb01da455a561f8651b90114e (commit)
       via  0bcf01ecf73e9be9e229ca3b4f91748963292492 (commit)
       via  5a7a368e37e8cb044385f7a0bd93952588b614e0 (commit)
       via  d40a1eca94a7e7c3d82cb03c09f68e674f25ed4b (commit)
       via  34af020380c21e3bea25ed5f2f65f1ed208f15d8 (commit)
       via  fac3de57832134d7d369eb5caec7b75c82736ebb (commit)
       via  d7ab012541fbd6beae1aa4fc060814077f84888b (commit)
       via  d70c95da1f1474689e9963e16b2369c3ca1dd02e (commit)
       via  a32f451ce9d7e71072a3ab66fec7d05b16b1f1a9 (commit)
       via  523e59e0dd743a4e64bc250bdbfefa2b11cc7724 (commit)
       via  87a5b8ebbcae6f4b661de1877026c5a567a69272 (commit)
       via  1f4817900540e77273c7684083986216ef92aa07 (commit)
       via  a0af076da0f1059f6de229b7983406583db995c2 (commit)
       via  dcd78c1acb1e93a1c4b74a1da6b6ff8a0cd52ca9 (commit)
       via  44b0024859129ab4fc4904e809a2447086a9c149 (commit)
       via  d2b4a3243571483992c4565150505a6c4b30f81d (commit)
       via  141e5bbc800637beff657c5c86f966e02e20340d (commit)
       via  ef5bbccbfe384d0a9a73f888e4cde669e8d4f9c7 (commit)
       via  59797ac65d9592f5868ab000a9c16aaa3f0f3aa4 (commit)
       via  73a0bea3f6265940279952c85c7efa40e60bd3d6 (commit)
       via  a56d839a1fea083776256cf239efe77ec6da7bdc (commit)
       via  4df15bd94b1758d368c3c131319e6cff841acfdb (commit)
       via  c1648c31e5522235b2f1a1742fa88a002353b5e8 (commit)
       via  123dff37f4d7eb8a0136799e9a9b91504f1a705a (commit)
       via  254d4364938cbde4b1d90f93a58ffc51134a666c (commit)
       via  a72b4edf3d7e47d48bee18b64b9614f236e40afc (commit)
       via  7835875a58a6f45d342106a1fe7d7b7a83684257 (commit)
       via  cb8a4a9f934efee8779bfac80d906c9a9344646d (commit)
       via  b1c16e50e93c662a12c49ac8f18b607656238361 (commit)
       via  f698b2db0b232eca879c0ce245baec8df5f5acd1 (commit)
       via  fcb21ed23acb3702540d07a98dd26fa4181eb109 (commit)
       via  f25bfbc22b5e983087f942140ce886da64e1ce1b (commit)
       via  c1287e83c8899e896bf86db807c14e523f5c20fe (commit)
       via  cbe56ea70c388b5404edbf5d80c4c9f9ef407afd (commit)
       via  2ef8bb1482de371b7b53e8be8f19aeebd03970bd (commit)
       via  5745bc9ed8069890b227552d1a22d97336dfb7d4 (commit)
       via  8e87ad5d17da5d7ca00c9c31934db4f60f4c232d (commit)
       via  26f308a2f6c18635fc9be9459121372879ec5fa9 (commit)
       via  ae85d44d033afb3ee89b1b073da5403d9e99a27d (commit)
       via  cd7b0306d711ba9b649621f9eeddb7fe606fa376 (commit)
       via  a1e0b73202b7b64b0f6bf49ee21764a085fd7f2d (commit)
       via  25eaae7433f9649c96733d3fc36287a1f24f6b35 (commit)
       via  99cd72e272b0a940dd95cb26f75a469855cb5a23 (commit)
       via  42c3c02172b08c2f2403be861a2a15f68c377983 (commit)
       via  32a32b28e1c3f1b0e3da0ea6205b5ed561ca02ce (commit)
       via  77d413a608bdeaf74e000a3ac102333abe14af0d (commit)
       via  9a3e6f354c516b8d7ce69f173b524b55f14e6d67 (commit)
       via  51280e45894cd3b25b0087e5917eba081d387830 (commit)
       via  9bc68cb51e2d99dc98782e7a5545e12531423157 (commit)
       via  2bc02dd72e75851ed9041035619be325b952eec7 (commit)
       via  3b3d4870252258b85b993522e7824c726436d83e (commit)
       via  545dc86cdeca1e56ec42c538be6784e6b26f9c37 (commit)
       via  3593302203b5663c5b87995bc067850aa5e83f66 (commit)
       via  5d13a8787e92dca88099376ef403068988d95d5b (commit)
       via  8c00d3f93913e2cdff6d6d8d0fd40718f5ec5da2 (commit)
       via  4531cbcaf96f5c0b234d079bdd95bdf5aa77b7cd (commit)
       via  5ae17c1e63db91e3a0e3c865c69eb84686e01a0c (commit)
       via  3ea3a84c90496ce7496dec749a663be40d5a1d83 (commit)
       via  334a46458e75b3979a1a4fc4d7442ee022a40dab (commit)
       via  7abb893404d8d8dd4da89a475d11ed96d3d9a969 (commit)
       via  10946613edebb3605b913fb4101a7c28a022606c (commit)
       via  74392eb0bf80525a9d38f13e8583ee049afbde37 (commit)
       via  2a59ce05bd0a86db1911f07adb942f10b8540614 (commit)
       via  0cb906be583e1c3d1f20cfba2cd09412fcd65a1d (commit)
       via  840cef17f97db7986b317f487bc3c7789b4aac0a (commit)
       via  ab8320d895cc59dcbbf53fa11612eb791db3a704 (commit)
       via  fc3a04984b7c93afd28d003079f2571085ab11b9 (commit)
       via  28b6e31e76e29832bc41db28e4aa764f52f09b19 (commit)
       via  2426cd1990acbacf19292e4589cf4fddb165d33c (commit)
       via  1d7d45f85ae189d166ba06e9ba81caf0f3a52374 (commit)
       via  b9ae27edf8b79b8322d1f8fa0a5487185caa3cf2 (commit)
       via  af0da34870440d38c6770264a1afd51dbb40c274 (commit)
       via  b566bc3e1f4c5b2aa3d1376e0982e71781260e10 (commit)
       via  cbe7dd2581bd76f09f1431857bd22beb1ed55e96 (commit)
       via  98f8e878aedbb5ec8d2ec0264010119dc2db2c41 (commit)
       via  c0c53637678bfa6d43b584fcba00981c4d8bdbcf (commit)
       via  b0d84c743691f3b75d0f47de609b9e2791c44843 (commit)
       via  a755942404c47f1a9341cc19593f7f46d00d8f2b (commit)
       via  f8c6d9a696b6d1e2280df6d57ab5797af515c6c8 (commit)
       via  0443e54d6ea5518e5ded4e90a36041f3df4eb04f (commit)
       via  2155b23c958ce10f8ade325add2d9372b99a7c8d (commit)
       via  4fc251c60082315ceaa048c1a830affc9f86c050 (commit)
       via  992e464be8f5968548dd7ffeed383938c306e48a (commit)
       via  8c055a4f0ff8659d4433aafce0ff478a78aa3b39 (commit)
       via  c9e7b404deb20aed5ec004b2253e6415915b4b93 (commit)
       via  c04b86940c4a3ec9bfb0e673bdebef519e33bec9 (commit)
       via  a9bd3195f738c0df97e4fe90a5609ba4d170f730 (commit)
       via  6aa49cb32493047d161016f05aa434a8ef8fc94c (commit)
       via  e3b426723e137d512f5ad33fda47f079d1e04959 (commit)
       via  407e945f53b5623e5ed01deb473b23762979a720 (commit)
       via  b3a37055c65399dffcd3def69d26c9c43418acf0 (commit)
       via  894b232671f1adeb4acdc7a5dd135087b3cbc224 (commit)
       via  db3934140540fe059bac10b898f191e41fa40ef9 (commit)
       via  dcbd38ad7fd6143c768225a207ba73e65b244909 (commit)
       via  629f048d1eb108b5072e255694bd730f8162ea6b (commit)
       via  785f2b3311c297b7ccab05e491a86ddfaf3e7f00 (commit)
       via  f745b1b462f58e0b441228ef3112bdd9e0427789 (commit)
       via  ca946771586ed82ebcd45b71b294e765d49aeca2 (commit)
       via  3361618a19d4bf4ee835c183a98d439b4c861f3b (commit)
       via  27519a39b79cc2dc7e3ab0f6a276b3aaec1156cc (commit)
       via  2fc5241ff263ac939d53169cb7eef67282546886 (commit)
       via  5d5c434ee01195071e176bb3821743cd5df01ed8 (commit)
       via  8f272d9b68214b42b98aee869306a1c635035be1 (commit)
       via  24ae0ad14fa1492633e1ab513cd3e265c9ad0e57 (commit)
       via  6af9e057038af834525962ad885e26b52e927f0a (commit)
       via  1b02a8026f17c9246f4ce667dcf5388c53cb3f65 (commit)
       via  9cf094772ca4d906e0cf37854a10d05952d2afaf (commit)
       via  1b224fff44c56b56e954d0dae63289a91d5c270c (commit)
       via  b090eee8e12770136771259e764ef1a3323d29b5 (commit)
       via  ab11d1585d32968abe3db2eb2fb094a8303baeba (commit)
       via  9abd4412c25a5f9e9c1b7717ff9992b848002ea8 (commit)
       via  5e2ac1718bfc55bd2724b74a7dd431d9df650fe8 (commit)
       via  00eb33c0a1d1f74f2dc3743f4519058cdb34fe3f (commit)
       via  655415c67a55e7a3d1799f72dcadd96514500371 (commit)
       via  9ca2813851bc5aee4f9c40c173219d594c6ec568 (commit)
       via  4b1596668958163746c9e8501e6ef937c7e10283 (commit)
       via  2c8b96b653857da4edb1d37fc538653e26facdd7 (commit)
       via  b5d38555e8a25b7e382ec97484b31e7add14ee6c (commit)
       via  25f05c4d604211c0e8b5cbf61e3de2e1ff6accc6 (commit)
       via  af81c6a82094e99e9ccbb9ac664db3c203c214d9 (commit)
       via  705b4687a23b151fc74415114e6c8df8d36a940c (commit)
       via  b7e600ded6264e9760576c1618ffea5885aae8e2 (commit)
       via  3b0962d41f1f0c0c835ae8971700124ed65ddd63 (commit)
       via  d06361449c25068c68259582c84fd5070a45503e (commit)
       via  dc85f42f3fc26a5b4815b51b961ea9223d4f6334 (commit)
       via  e3c21f85b4c55762b356a605a645afb4c474429d (commit)
       via  587e5e26edbdaeb89ec6fa11f99cc91fc3fe11df (commit)
       via  17676f047fc5bc7ea92d48beb0f52b1b86ce7f35 (commit)
       via  eee2cc00ca2f0a21ffcea8d4d94610983e54868a (commit)
       via  3f77c647436d217a77d9b816262f79e0878d7923 (commit)
       via  d088d344f2e677cedf6012e7f382326858c4bcbd (commit)
       via  29cb82362a4d833c1a153d84be01a89a4ba06fea (commit)
       via  5ecf353bd16f909c5fe6e6145b3d8bf90935a143 (commit)
       via  6a6d989d7eb2c16591be25d38bc8d6c1faf0c51c (commit)
       via  2252d3f680e633e33393273b9513d1ce019766d4 (commit)
       via  9ac5418666c2b2271ea7ee56603292cfd446a5ee (commit)
       via  5a97ca2cb10e7e800a459670f5bc9b0237131cfe (commit)
       via  4e7c9b630407b125b572274dc3f493be487b7692 (commit)
       via  baa41d7f8dc9ecdacc9107516f0ecf2afef9e80f (commit)
       via  5bfe8a369606d742cb50fc34a437ebe6f9630252 (commit)
       via  7deb27ca53df3f317755664e25f95dcc9eabdb1f (commit)
       via  79732f4c33178a61bade7835d67a953117c637aa (commit)
       via  525b3a6549b5dd77e777c189a2e6e233d837fc8d (commit)
       via  fffb8a4b4757b057e5e964274a4b23bfc27aabd5 (commit)
       via  e228ee5b5a505b9965d90ba0c9ba7963ea5e7d05 (commit)
       via  2e6f550913af1b72a933da66da54dde014f5c9bf (commit)
       via  4430d1e4406a08f88f87ac93c380181b8c5ed9c6 (commit)
       via  37b6ba75e9ae2eed80c88413e1df1809a8fff699 (commit)
       via  10c90b26afa857f6d3f1e0184d2533bfc171e3ea (commit)
       via  03f75e32374b3490c8f6d3696c300a1af0d5d139 (commit)
       via  f7de20f4c11cb49605551fc6dc0b778803f0fd38 (commit)
       via  7976bc485545b985a89eb751923d4c4b3cdd4703 (commit)
       via  adf9654673f2c57d59b8171be8535d30f3775dc7 (commit)
       via  a9050253d9494902f21aaf6353f928f2d4662315 (commit)
       via  d0e7c4835fa199b8f270822a22cc158d38abb9e7 (commit)
       via  df7ae3bc3f474d15282eae829a35ed0ccad441f5 (commit)
       via  b7ee8b84b7c77c9a20ff3df47b003070fd25e302 (commit)
       via  a6c69113bea3cca9394c497d190f202e8341cbb6 (commit)
       via  059e8898464800ef6d32cb6722d65477feed7582 (commit)
       via  c950a25a06ea0ef40cb257ce10e0d4ecd14dac42 (commit)
       via  cbd31f94b86f86eb5c799cffb8ea610e2ca75e4b (commit)
       via  48c36c10770bf5e1e51655c67780738d9222d032 (commit)
       via  199b771328ed7fe20f0b912efc985da13e594e4d (commit)
       via  1b887a5d57c915d8372534d971630281cc52c501 (commit)
       via  7f5e1b3d9c22221c08ef94e296eae0bb8adb63dc (commit)
       via  52456c0c990d817faad5165ba01a336796b1634d (commit)
       via  4175d758f682ee314d08a63be5126402d9b8105b (commit)
       via  79333bfd3979016b20bd750bf0ba31db6e843b4f (commit)
       via  e1b9c837c77d58462f8861b1a67485399436fe5d (commit)
       via  00c197b67fd9baa9fa112f4c8a69bdb0ececf147 (commit)
       via  2799609be2989d9b66651d0cb18c1f57a9c5941b (commit)
       via  dbfaac40bee1826046a01b4aab99608581b2328e (commit)
       via  af021a5f0a3d0913eab56d593b14abdc267810f5 (commit)
       via  c6562afd3370ab4972771286e71a27557befc9d1 (commit)
       via  76ed341718f0694bb58f0027f207eff51dae478f (commit)
       via  169e66dd3e28a9d2ca70fece895bf31ff940d89f (commit)
       via  21ce2dada02016a9cf795c8325985d2dfe099a00 (commit)
       via  590873fbec21bdeabf42b35691eb54bff4898a25 (commit)
       via  30d2af5a1ea7eab62c0dd4a3fa40e5a371990e5d (commit)
       via  c5ffe040b9533fa0e4d94b68e0371f29ca9c75ed (commit)
       via  5b00ae2e64bb74ff92abd9c510b205747fbe43f9 (commit)
       via  12bd5d09058ad9613a70b14f17e14fd8f0446123 (commit)
       via  c492a2056793a8861c115f895f7cfa48e75a89c9 (commit)
       via  e2ead2595aff7c38544cbfca9bb06afbcb0ffd3f (commit)
       via  1caa0dcdf6353763d7ba4cc585baae980fa30852 (commit)
       via  fb2a2d0155a495e61f009b3949cee23fadecaf04 (commit)
       via  c063681486d8318870382ae6575ff2e2b8c1025a (commit)
       via  dc7d65764d98d6e5bbf5f8e807483dda09848084 (commit)
       via  bab59d563851290b5e2bb12208479854f8f75c9e (commit)
       via  c93d795692bc71abe8eff60ec8823a10a4e4a4a7 (commit)
       via  ff6170061e52dd85864d2e9e490afcce0fe390c5 (commit)
       via  54945957d0ee696cec125b258c592544a361aa5d (commit)
       via  4ab14673e3cefc7208cb18a2beeec6f92f2b9a8e (commit)
       via  97ef92b61c61df487ac194ec95b9b2f1fa8b09f8 (commit)
       via  60dcfd6dcc195c4b0887eb75acc5b71571c0da1c (commit)
       via  ce05b32400faa225d632597c17c7a6ab688e2597 (commit)
       via  14ab5a072a86f08a56b30b5c3f0ecd4c92aac06c (commit)
       via  f4d2c54a2c6f82029cb9152ecf2e881b94436969 (commit)
       via  df0818671f63ec42d65c2b327f485e041628b7f0 (commit)
       via  9c51a0a09ad1946ea5d4a468278800d61da78469 (commit)
       via  5e170be4118309e6138bbecef143f88fecce8db7 (commit)
       via  17150cf28750527c350166b6db984ab042d9c534 (commit)
       via  779c09aa1d951e3a349980c690a79c1f23aa27a8 (commit)
       via  fed894770446ca39815bb96ad7f64bd1ab980333 (commit)
       via  09c57eccc785df70425ee08aaa24d37e39dbb46b (commit)
       via  ed2b0371ae687d373a2c56e53df9a27034380535 (commit)
       via  dc7d01f89b664abcbdf482b9db6e5e8a1a369e04 (commit)
       via  5ffa21480181cbff600a90f2cf75803b9a92a006 (commit)
       via  33802e0c65c1e3755f98c463bd2ec89c6bc322cf (commit)
       via  e19a153219a3d192fb78266e13916cf0c04c03e9 (commit)
       via  7829277217f388316dd7477cfc680a8a2e3b2e6a (commit)
       via  d95de5f29b7ce8648854a00a5cb4dd6b7bbd5514 (commit)
       via  b4000375741909e713cd37bff35ac3380e8cece5 (commit)
       via  4e9b543ca711980309b41659631821bca02fa6f2 (commit)
       via  9fda0594403d6fded1e4d5b62c85204f10da6927 (commit)
       via  71432108563f4033b527818687b7c8484f4af882 (commit)
       via  3c7511caf544ae09f484aaf8d531ca8007db56e3 (commit)
       via  d82b9260fb1deb5406ae7c0a3465195804ae662a (commit)
       via  df2d1b1a9d09a8bee968921d05559cb1a12b273c (commit)
       via  db36e6d380b7d85a751a0d2c15646c325cc9f1b1 (commit)
       via  7d7a8d01a95f2481365ce7068891b9291871d1a1 (commit)
       via  2f98c2ca6d4b960a240ab609b608a5d816eeb23d (commit)
       via  bef5252724d2da5345c18a3107606103cb011f90 (commit)
       via  cb7d8ada99f5b24f9961cef5bbd8f2f3250652b7 (commit)
       via  9edefd96a4d61dc4bd6e2bf470e785cb2e34828d (commit)
       via  bc95274af418b3a64353b2cb2578cdec43d204e8 (commit)
       via  b34e7cdc45380c06429d2195396f0512620c79b9 (commit)
       via  b2c434d62c9c7bcc408ddde51e3532d8b9d74013 (commit)
       via  9c6348ecbc8f5403aafe2b3dfccd678a60f921c0 (commit)
       via  7e6e1b7ba0c797e4692bda59ea500f953d9b7be5 (commit)
       via  ff6025edcc99b6344d39004269547a75e1d05e9b (commit)
       via  083fd1fe975eecac87f25139fffce88897bc2d44 (commit)
       via  3b8f231cc24be0814b3eaea14d2115bafe78f9cd (commit)
       via  b59367818eaf4d8c8d16ed5e118385ccbbd89751 (commit)
       via  ba8aaa6a6a30b6ab79d52450bbb431d437c3cf7e (commit)
       via  fa431021f2637a6b135a355304ceb6be0cfb58e1 (commit)
       via  f7949d1e46904fb58bb3d51b8effa249dd165523 (commit)
       via  23ff7f02c3b589341921395ec8ad1447cc367785 (commit)
       via  31f7ce2b6153be4fe9257ae911604d7c2e183a7c (commit)
       via  c72773c7f45158568754c7d639fcc25f268b7c9a (commit)
       via  0d7c69487a7fc00e9648cf622fe2958017353f18 (commit)
       via  e43ff95aa19afba4b07c7690f949c5aa45f594d0 (commit)
       via  aa4ec37a77ab65da8058160cfbf83433cab94e04 (commit)
       via  072d9f0797b40068aeb99f1c68eaeff72f26a34a (commit)
       via  a05b2746f450043afcb8c49bc632425eac1c6974 (commit)
       via  313de70a8ecc3fabb8692bd353dec86ac9950002 (commit)
       via  94439c60629cef6aac18f7242fc8303b03ca42ed (commit)
       via  ef7a28f6232c768b16489b8c7f525b301ad5e2c0 (commit)
       via  7aab47898933c308873742a568c3fca14b2a7327 (commit)
       via  f5824d8c4ffac2bea9ef5d3c05a60a32279d1603 (commit)
       via  6aa6cbdd0ea0dfaaa04c4fd3a08e59ff84a8f73a (commit)
       via  0ecc01534076197f8e86853b90d2636b454daf7c (commit)
       via  4da5874a59d5232ca1c1abedadb1e47d5b0ad14d (commit)
       via  fd441ebeadaa49e9eecaf1d20ce7db88d25d5975 (commit)
       via  0adc65021d1aafe2ae9da3f11c9da81794653b11 (commit)
       via  f46517da24e979c288e9e4e21fdf812520cff19e (commit)
       via  62519305dfb30216714cb17363e0fc76b13677fa (commit)
       via  8e0d3e31414b5e8ed5c0ecf88c91850e0f233b4a (commit)
       via  61cdf2ccc9350cc17c8d5f9381eb90e6d8ec6358 (commit)
       via  8c143040bc70c63a9b6c031584ed07381bdf603e (commit)
       via  bce184dc2426105f6d45499e9cd99b59981b8dcc (commit)
       via  1544e6e84655ae58ca65aa4456c037ce471117bf (commit)
       via  fd9bd300bec3838ee3a5b8424938c1cc5a2a781d (commit)
       via  d503ff5fd70d310d5e71ae21f2ba8568d293b2f1 (commit)
       via  2488744791e04650653d75c1b34b06e8d2e58839 (commit)
       via  404796461a1ecf64c7290c9c5a4f52c98f69227c (commit)
       via  b983f9d4b5f807755878e6575fd30c8cdf8700f2 (commit)
       via  bb08b9f3d93019a35ed99e1eb08fcb26d91cadab (commit)
       via  e23e0b682729340266add858a1db960f40d655ef (commit)
       via  c4eb4f7f4410647102dc53718535c4fdb53fd260 (commit)
       via  3512bdcef702f40f549babdd8ba2ef945c380b97 (commit)
       via  64e3ea90b905dcb94e7976910f0421839808c5fd (commit)
       via  e7c7ba09d9b0bd859b0561009be5eab5020593ed (commit)
       via  1043e0e403e1e950b1ffec7803236b2e62c72be7 (commit)
       via  f5c886d1beaf8481516c0c7de3d240f3d95d3c69 (commit)
       via  e292e02762db36da86505c99a8b3cbb0f10f2faa (commit)
       via  89c96799ce2d7bd6fd28544a6082ac86240065c3 (commit)
       via  9c10e3cebd16aa24714cc152d46055e3c7d61db7 (commit)
       via  49ff650f0b1178a3e7d0e4e9fb83b13d3eaf9d8d (commit)
       via  8089ffc6c5a6519c310362753071f9aa84a0e46b (commit)
       via  07f94a47fa2f5c607b920226ab675baac245bb4c (commit)
       via  267cd4701eed4f7286a9953f4837807c4be3f13a (commit)
       via  ecc1e5c52975b654ce934e7077cad0b92b9c566b (commit)
       via  e4f5461b3c0c4c7376a532762bc50d38b5456971 (commit)
       via  d80571561d5b27eb7b486757a42ceb8348c15f1f (commit)
       via  41b7e4f0a6ed36537ec424f7179d28a6ad1deb9c (commit)
       via  fd0e01d6aee77a5f2abe7449c66a8de225e7c46e (commit)
       via  ab726bc047ace6c9808bd6329100b411091dfc5e (commit)
       via  4c4a1b2269e08565590ee523540e142a767fe79e (commit)
       via  2000ad879def1bcb21c69a54e80ea840ef7aa4e0 (commit)
       via  d57ca4e4cbbb2fb14f2ec6584f9e27712c3f8d85 (commit)
       via  1b316edbaedef08c97798d0d2bd1cc633a6e2d77 (commit)
       via  d064e611972d41a2cee84fecde071a5cb0b857a4 (commit)
       via  2ebc2cd4a19116249921e9c5a17b5a675669c4af (commit)
       via  607dfa19ad9383f5b37643a6308593ea2893e574 (commit)
       via  acb0ac5eb7b0ffd1a674156145a5e1c45d4ae58e (commit)
       via  7584ed95ed7da7c0d1d39308a0f765cd7a5a450a (commit)
       via  9875d164b8bae823ba50aa63ba2cb795fa45a45d (commit)
       via  1d2e611e871081adaab99944df01099ada1adbc1 (commit)
       via  4efb1b0899a27905e55700f019b59835523de665 (commit)
       via  a23b02a93a8ed14b726f3b1377439948ba343352 (commit)
       via  8db19bcde085f3cdf3b98f84668f2ab1520dfab9 (commit)
       via  818af05a6814f51a463a8973d5efe94a21c006c4 (commit)
       via  7f0b7a870248000e9527870cd1efd1fb4b31444f (commit)
       via  198ff61d2be54cc31eb09602a402f60f32549cc0 (commit)
       via  5ae219807143643f3f6ffd257f901519cd108c39 (commit)
       via  7f69d3a31c7514ae96a70a98fc83b0a0e564c354 (commit)
       via  5739eb00af23e3a99801a9835d66d448718fae54 (commit)
       via  65898da466318e5d43fde742f5e4220eb7f6211a (commit)
       via  55f2857d75ed3ac504ab56bf63947f55906ec190 (commit)
       via  f5fa5a28a433f93aaee65293679fc64bddd3618e (commit)
       via  8ae61af3c1e9cdd417858bc8f50c2e70356bbbd5 (commit)
       via  9b2fd75a0fa983c4c0accd0eae42bbe8c9bebb6c (commit)
       via  0be25795c6746f8f2a16e1381f7bfadb688e4b9e (commit)
       via  2aa417878747b9a4488cb912b464a935912d3676 (commit)
       via  ecc8330075867410def9e95cf6c85408b9d3364a (commit)
       via  455a48ce58ddcc795f8bc6447d6c2b3b2c3edd89 (commit)
       via  f8c6044b768393b0c23bacc05c169c0dac3422ed (commit)
       via  7c54c736a42fe7b7989f68f6ce6947155ddeab2d (commit)
       via  aaa0bded726c6e1f6ed13884bdc84154af083fe4 (commit)
       via  e67e41c485387f693e3c2ebfb07cf86fe40df804 (commit)
       via  02a133d472a0a3cecf208f658141591ea83ebe35 (commit)
       via  3300b2d2b1a199d666bf261a1882aaaaa0d5af5b (commit)
       via  f61379ef40c892685eccf1d34513d6a91df01898 (commit)
       via  3b7222b35e4ec15902804b9b1741b9e0f2d45646 (commit)
       via  a19829a213fe39f3705dcdd7c76a6d025a4d3a75 (commit)
       via  44f9398832b365b5323a03c2948b5752217b07a2 (commit)
       via  38b6002b3638d173be6b43153f8b3471a702e21f (commit)
       via  06ee5810059d3fdab1851e1fce9fa955750e69b7 (commit)
       via  f79c4c78c48a46bbc8dffdbf3034a2d42abc85c6 (commit)
       via  ec387be2cb89096fac6c690a1cf9427850bed5a7 (commit)
       via  ddf7cb15af1271dd83d65bc79c0c318cd0bd44eb (commit)
       via  1b7b06fdfffbcb8da77b870c9a7dfa4857bbc163 (commit)
       via  3fd5fd38dfdf85074d96f13d9893cfb479ff0681 (commit)
       via  9931669f97289c194a68995652042df36719cd5c (commit)
       via  f52dcb091e2cfb821ef96c21679a1449d45d4780 (commit)
       via  cf1c75514a0c54c3d777f10b1785164dca9c8729 (commit)
       via  4f78548ad62f25816529bb117c9721108daa3f1c (commit)
       via  7628f1be78eefdafa14d2aa9b0f549ccd8c2e7d3 (commit)
       via  650bbd4001e9a11f2586f8e3a148946e2fc5e346 (commit)
       via  a1de19c8b458426a71dd22c9118ecf771c03cfb8 (commit)
       via  6a5188b46e51f9476cb8d700bf8143db2206a40e (commit)
       via  ac08ea40a32b8ac7dd946ae72326d1e31468dd9b (commit)
       via  e672f69dc1588bac311978f494e5e17326672047 (commit)
       via  1637c4e388ded0e019225d53fed3e6bbefd43bde (commit)
       via  5a3f881ea489ff202135f6c90ec9fa87eedee86d (commit)
       via  715d9f8502473b20049b00554e425e844afb84ee (commit)
       via  a24a6492ffdf0880d32d5f8daef2114715155414 (commit)
       via  fbaa0e3206382f98495f0b857594d46ddb422fb9 (commit)
       via  899e976ba9d0812d346519d9546cfe568c1d6ed5 (commit)
       via  bdcdad59c13f5645b38c24e9a4c1ebab781d6b6d (commit)
       via  0e685a00faf3a288ba1e1f988064b7d44947a0b3 (commit)
       via  8f896b470297d1395886705b820e77a26271d04d (commit)
       via  3616bafc7f9ca245e9ac3573ce154361a937bd95 (commit)
       via  c446ac44239f3736637bc9569d66d9990e20d654 (commit)
       via  acd000cd2f669995413f0369ef46a4a7ecd6b584 (commit)
       via  e0d75a0b11de1e2da7478e2e3d6aeb012681c891 (commit)
       via  4a66761a7c0cab48e70c0a70449c2dd235616865 (commit)
       via  b5f5b6d40dda3b2b4b380819c8363561bab9d14e (commit)
       via  eb3db8c71692ade0d1b855dac42f9c43ccb4a43b (commit)
       via  3bb8c1f192658b2d8cd68e88ca701096f32e9c34 (commit)
       via  b7f62a9ee5e2ae511499d4c3ddbaffdb423205bd (commit)
       via  c1ee06620f0af633e6dc51cc5590890c232e6af6 (commit)
       via  40f6fe829bf0648ec03b88f33453a2413b9775f6 (commit)
       via  9c146da5331c16ff92ac9436dbb1928bbfacdcb6 (commit)
       via  c9e084a9fdd46f3c067c40f55ac0d4241d011f4e (commit)
       via  f20064a8ac3157403df23c8dd0c202ca1a0e7841 (commit)
       via  8b956d6a100f9a9db2c0bd45c79c28830dcfba7c (commit)
       via  526592d7e52c9e4fb3b3418dbccd71c931e524d1 (commit)
       via  277cd59580de408be7714bc840495699e957e345 (commit)
       via  c668a68e40499b291793fcaa280c5b7b09222509 (commit)
       via  964c138438e9e94e8095a985d803fa75d0512e34 (commit)
       via  22bd25dceb88596c6e337c50ac5d068fa765fb3b (commit)
       via  9db8d0904c1673f8ae321a30221b06442b3ab159 (commit)
       via  5e818d77d453421417acdb292e27010c0053cd2b (commit)
       via  5cc2c8622a03e0f63715454a58f31be6bda91767 (commit)
       via  9b3c085e22dac69f657ddb55c07a172b87c02378 (commit)
       via  4cf6471fbe25d4b5ca07cfb08f2ef230e708790b (commit)
       via  0bfb709cb086d8b4bb68016dbfe194aa4fa1ddfc (commit)
       via  af101df958f47c999cc3a27e4d056d6ef0aed04a (commit)
       via  78be74cdcd313eb307718535e54ba79962a91155 (commit)
       via  37a7281b1e787264b80b9af03fd0fe47d50f93eb (commit)
       via  6e5f510fba140a1e4712fdb032dc05f73dfc790a (commit)
       via  f68775a16aaa8f9bf6240e0567aab3094dafb850 (commit)
       via  2e4187d8d935a7b4623f398dbd247379395743aa (commit)
       via  e169cf3c9d1ea1a516d58a875fae2ee93bbc4c36 (commit)
       via  eed205aff7f94fc578dc48d40ac80aa43794ba34 (commit)
       via  ab9c34521252bb3d81fa77868eb3ea7923eea45e (commit)
       via  6cb973ff77b4d0eb1b27f5217b2eac6d317ce2c0 (commit)
       via  98ba72c1b8a0f05d954ffd7773d6a11f0a980fe9 (commit)
       via  7a27317ba48f4e447e5ab76fd793d6ba589a46e3 (commit)
       via  6b999cae54d183fa744403463c39ffbe6291cc95 (commit)
       via  5bd93ef0725814e30ae15ce94a1e65c6c3abc0d2 (commit)
       via  33cf28d7fb8c3f83521329a4927e4985dd3593d9 (commit)
       via  17940330a40a3a4a1a62cb90758291f96b1ef71c (commit)
       via  820b860b33c7976ec6ac718b5c4bfae473cdd50b (commit)
       via  18310742c22c57570cfcb11401b67e67849c2bee (commit)
       via  bf03f1b7aead0cf2598cc42dd74120e58d3e3c12 (commit)
       via  82161ce9865200f03e942e88f5e806df29bfab1e (commit)
       via  a1824516fbd28c98b873ec947bfcd152a68909b7 (commit)
       via  29b06b9b4fd572d2ff4a3ce678d13ec0e19a4ab5 (commit)
       via  cd899b81aa4160cc6045e3e3dc1050ee5b648e37 (commit)
       via  c1d7dcba0072e53c6feda05d633bdf03f52c8d4e (commit)
       via  acc33ff6db2942e6d9c3a2533391fe5e7402f788 (commit)
       via  fd0f96bfe4e058bd50b058cdc9575ebba5d9ffbf (commit)
       via  3f9cbabcf83be9e5f001bcaf4b5f7abd63372a93 (commit)
       via  6985a3a321246e81aaa0de5d1d95ddb08c4f0336 (commit)
       via  185311af534c65f72c5abb9aa4e82731dfe2dff6 (commit)
       via  7732d9ea39d1f524d343531bc970ab47694cfcdf (commit)
       via  7ac4f8749577593ac252ffadb646bceacd8aba98 (commit)
       via  89f4f98309cef3708f61489594f5660106e942dc (commit)
       via  2925dc36272f91ee3a7120a59e3dae39116458cd (commit)
       via  7f415a0bbb5a33c71b32ca276bf8a21154c8fa6e (commit)
       via  789bd4b523ee4c8d1f90a60a8ee87537aaab7f21 (commit)
       via  044bf06af94ea9f45029161ee631ac559d0945f2 (commit)
       via  8bbb459317ab28eaa328670781731f973e31f14b (commit)
       via  2cf5e0b288d1483bc1c0b9e20948b61014672cdb (commit)
       via  94bd2cf31dd21355311983e9397c9b0acf8354fb (commit)
       via  e7707ffde4cabe493a2e0d058a8e5700f1f399a0 (commit)
       via  b775519e3cafc1729e6112313317b3a9535c685a (commit)
       via  5689d6b93cd757572cafe340a5b42f6fef1887d9 (commit)
       via  19f1bc89786de9a0fe52fb9cbc276fcbf23bedc3 (commit)
       via  c55a56b5d862cb3e7a9e506297e58cf4bda0ab7f (commit)
       via  ccac8100bd6e7924d36aa2eda228ce5c03432ab1 (commit)
       via  46a9418d8696b085bac427d00231457ef715a43a (commit)
       via  70355f3da9f5065e7e6dbf8dd469f524e4a5542b (commit)
       via  e74d39b47c9a731d1b04e92b2a959194fee0e1ff (commit)
       via  5690ea9bf81d47cfd28a3e30a54332c6f921092c (commit)
       via  a380988a973fee7f3ccd70c30087026cd593da77 (commit)
       via  afec57f8273c98b4fd78e4f7e612949f74ab5375 (commit)
       via  f027dc51b832e0249326bab4258bf70ea28e8805 (commit)
       via  9552b5dc6d44ec5c2ac19f887ec609ddb18e5947 (commit)
       via  887c3363dc4f1ffb8cff5405bb9a9f5122aed1ff (commit)
       via  f0bd18e11efef2c9a7fb07cb43e761338ae5be84 (commit)
       via  ae38bd482e93a7ee68a76f20831b7cf8b7fa61fd (commit)
       via  9b2b5b6c623579057e9322bd44a7342d0b08ee92 (commit)
       via  ddc54a061616e806e49661d6f863f041eb1dffc8 (commit)
       via  7cb38f2a04e068fe36002148f3b1963f906decf4 (commit)
       via  d4dbefa465df2b92c31b666d881f0eb01d9ec9ec (commit)
       via  c67087a80dbfc64fb67b0dc79291a3a9781ff02e (commit)
       via  5bd0920a899e520ecedc281a6c1324819dfffb71 (commit)
       via  3c27815a3c237e318f9ae42a1c9c5c74158ebb59 (commit)
       via  73493037c62ff899ac70024ea868d80426a26102 (commit)
       via  825d8ed76aa511cbfa75bdb0c8cca6bb2ec387e8 (commit)
       via  94f6a1917ba71f7beafa5e1164b6becebc0149e2 (commit)
       via  94eadf9dd6fa51060078fd9142693f5612b5ac6d (commit)
       via  b6a2ea940cc61079d072f9e2f7b7d8387b5f809d (commit)
       via  3dcfd24c42684c578f2ff806b021c009b45832e6 (commit)
       via  ba11b654e61b5912851bc7fcf239131be7bc13c5 (commit)
       via  f8e020101fea5bb81987929597032e3c7f34212e (commit)
       via  c9c3c3b325b3eed1531403e355b72c51d8bb61d3 (commit)
       via  1893a2d9f770e1f034424a7099315658829f65b6 (commit)
       via  d313af8df220232f24cae1494070bf86105f0346 (commit)
       via  3eed36483f4e1d7fa8ea6b900440f4c6342874ad (commit)
       via  8a99641b178876e1c309bdbcfca680807c1b2418 (commit)
       via  de72f1d32110cdaa5ad5a5ec852c25559a23a1a4 (commit)
       via  bc7e72a7937d96790c2a5d9e27fc004b44d063a7 (commit)
       via  3c53fd28fa796b8bad33cb019b67c5eeec479845 (commit)
       via  d4761e94c9e13c9876a32520a4144de4f0bfd7e1 (commit)
       via  20d91aae28f89c4341b0735c1d560a3b5fdcd53c (commit)
       via  efd96834fd72d0001799541660c962c945a1f571 (commit)
       via  fad0b1dc6453d84ae431c4b4545bb849cae1c730 (commit)
       via  16c44dfbe55ed841c0a3472995f612af775d2570 (commit)
       via  56749ef21a5a04ab7fddeca907eb92f570383b0a (commit)
       via  c0ca70ec242c67f55251aa53e3e33235f3b85c15 (commit)
       via  4ed29b591ca9128b5e2c21ad335120927bd51366 (commit)
       via  b56ea0ec153cee4af8a99bc7cdc82512261e8b1d (commit)
       via  a2ffe78ff54f7cac7f5b90c15c6179b3172ff05b (commit)
       via  13074f54a29f7d8e01bb58e292399738afae2466 (commit)
       via  d8ace69668441585144c119ce5a70a8f5bd39300 (commit)
      from  adba6bf145a03e03a611fae673dbfe936e8eca1b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit cb753c3ace486a17e1f3fbb3cbee29dfd20ae68d
Merge: c45346a 28daa75
Author: Stefan Monnier <address@hidden>
Date:   Thu Aug 15 00:12:24 2013 -0400

    Mark merge point of websocket.


commit c45346a3c823eaafc09b96d2c33ba945a287346a
Merge: af5a174 714dca5
Author: Stefan Monnier <address@hidden>
Date:   Thu Aug 15 00:10:38 2013 -0400

    Mark merge point of js2-mode.

diff --cc packages/js2-mode/.gitignore
index 0000000,c531d98..c531d98
mode 000000,100644..100644
--- a/packages/js2-mode/.gitignore
+++ b/packages/js2-mode/.gitignore
diff --cc packages/js2-mode/.travis.yml
index 0000000,bb0a9e0..bb0a9e0
mode 000000,100644..100644
--- a/packages/js2-mode/.travis.yml
+++ b/packages/js2-mode/.travis.yml
diff --cc packages/js2-mode/Makefile
index 0000000,f86786f..f86786f
mode 000000,100644..100644
--- a/packages/js2-mode/Makefile
+++ b/packages/js2-mode/Makefile
diff --cc packages/js2-mode/README.md
index 0000000,9065cdf..9065cdf
mode 000000,100644..100644
--- a/packages/js2-mode/README.md
+++ b/packages/js2-mode/README.md
diff --cc packages/js2-mode/tests/externs.el
index 0000000,7860058..7860058
mode 000000,100644..100644
--- a/packages/js2-mode/tests/externs.el
+++ b/packages/js2-mode/tests/externs.el
diff --cc packages/js2-mode/tests/indent.el
index 0000000,953b8a6..953b8a6
mode 000000,100644..100644
--- a/packages/js2-mode/tests/indent.el
+++ b/packages/js2-mode/tests/indent.el
diff --cc packages/js2-mode/tests/parser.el
index 0000000,3c05c4b..3c05c4b
mode 000000,100644..100644
--- a/packages/js2-mode/tests/parser.el
+++ b/packages/js2-mode/tests/parser.el

commit af5a17495f80e22dae84f22f2b8b4b1105ca102b
Merge: 57560f2 b8bbe20
Author: Stefan Monnier <address@hidden>
Date:   Thu Aug 15 00:08:37 2013 -0400

    Mark merge point of ioccur.


commit 57560f2651584873760f4034259935c3a568f1c6
Merge: 6817d91 ef861de
Author: Stefan Monnier <address@hidden>
Date:   Thu Aug 15 00:07:07 2013 -0400

    Mark merge point of ggtags.

diff --cc packages/ggtags/Makefile
index 0000000,02fbd33..02fbd33
mode 000000,100644..100644
--- a/packages/ggtags/Makefile
+++ b/packages/ggtags/Makefile
diff --cc packages/ggtags/README.rst
index 0000000,e18db58..e18db58
mode 000000,100644..100644
--- a/packages/ggtags/README.rst
+++ b/packages/ggtags/README.rst

commit 6817d912be60c8d261856ee7c0ce959561e17f32
Merge: e5bc365 2619e05
Author: Stefan Monnier <address@hidden>
Date:   Thu Aug 15 00:04:04 2013 -0400

    Mark merge point of f90-interface-browser.

diff --cc packages/f90-interface-browser/f90-tests.el
index 0000000,d653882..d653882
mode 000000,100644..100644
--- a/packages/f90-interface-browser/f90-tests.el
+++ b/packages/f90-interface-browser/f90-tests.el

commit e5bc365387b8c37f425e25e233f1528fa20c369a
Merge: 4861427 0695539
Author: Stefan Monnier <address@hidden>
Date:   Wed Aug 14 23:49:37 2013 -0400

    Mark merge point of eldoc-eval.

diff --cc packages/eldoc-eval/README.md
index 0000000,e69de29..e69de29
mode 000000,100644..100644
--- a/packages/eldoc-eval/README.md
+++ b/packages/eldoc-eval/README.md

commit 4861427a5a8b64fc6ae555a140129c27a1d62175
Merge: fae643a 764d2aa
Author: Stefan Monnier <address@hidden>
Date:   Wed Aug 14 23:47:26 2013 -0400

    Mark merge point of company.

diff --cc admin/archive-contents.el
index 072d03f,0000000..e2154df
mode 100644,000000..100644
--- a/admin/archive-contents.el
+++ b/admin/archive-contents.el
@@@ -1,531 -1,0 +1,532 @@@
 +;;; archive-contents.el --- Auto-generate an Emacs Lisp package archive.  -*- 
lexical-binding:t -*-
 +
 +;; Copyright (C) 2011, 2012, 2013  Free Software Foundation, Inc
 +
 +;; Author: Stefan Monnier <address@hidden>
 +
 +;; This program is free software; you can redistribute it and/or modify
 +;; it under the terms of the GNU General Public License as published by
 +;; the Free Software Foundation, either version 3 of the License, or
 +;; (at your option) any later version.
 +
 +;; This program is distributed in the hope that it will be useful,
 +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +;; GNU General Public License for more details.
 +
 +;; You should have received a copy of the GNU General Public License
 +;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
 +;;; Commentary:
 +
 +;;; Code:
 +
 +(eval-when-compile (require 'cl))
 +(require 'lisp-mnt)
 +(require 'package)
 +(require 'pcase)
 +
 +(defconst archive-contents-subdirectory-regexp
 +  
"\\([^.].*?\\)-\\([0-9]+\\(?:[.][0-9]+\\|\\(?:pre\\|beta\\|alpha\\)[0-9]+\\)*\\)")
 +
 +(defconst archive-re-no-dot "\\`\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"
 +  "Regular expression matching all files except \".\" and \"..\".")
 +
 +(defun archive--convert-require (elt)
 +  (list (car elt)
 +      (version-to-list (car (cdr elt)))))
 +
 +(defun archive--strip-rcs-id (str)
 +  "Strip RCS version ID from the version string STR.
 +If the result looks like a dotted numeric version, return it.
 +Otherwise return nil."
 +  (when str
 +    (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str)
 +      (setq str (substring str (match-end 0))))
 +    (condition-case nil
 +      (if (version-to-list str)
 +          str)
 +      (error nil))))
 +
 +(defun archive--delete-elc-files (dir &optional only-orphans)
 +  "Recursively delete all .elc files in DIR.
 +Delete backup files also."
 +  (dolist (f (directory-files dir t archive-re-no-dot))
 +    (cond ((file-directory-p f)
 +         (archive--delete-elc-files f))
 +        ((or (and (string-match "\\.elc\\'" f)
 +                    (not (and only-orphans
 +                              (file-readable-p (replace-match ".el" t t f)))))
 +             (backup-file-name-p f))
 +         (delete-file f)))))
 +
 +(defun batch-make-archive ()
 +  "Process package content directories and generate the archive-contents 
file."
 +  (let ((packages '(1))) ; format-version.
 +    (dolist (dir (directory-files default-directory nil archive-re-no-dot))
 +      (condition-case v
 +        (if (not (file-directory-p dir))
 +            (message "Skipping non-package file %s" dir)
 +          (let* ((pkg (file-name-nondirectory dir))
 +                 (autoloads-file (expand-file-name (concat pkg 
"-autoloads.el") dir))
 +                 simple-p)
 +            ;; Omit autoloads and .elc files from the package.
 +            (if (file-exists-p autoloads-file)
 +                (delete-file autoloads-file))
 +            (archive--delete-elc-files dir)
 +            ;; Test whether this is a simple or multi-file package.
 +            (setq simple-p (archive--simple-package-p dir pkg))
 +            (push (if (car simple-p)
 +                      (apply #'archive--process-simple-package
 +                             dir pkg (cdr simple-p))
 +                      (apply 'archive--write-pkg-file dir pkg (cdr simple-p))
 +                    (archive--process-multi-file-package dir pkg))
 +                  packages)))
 +      (error (error "Error in %s: %S" dir v))))
 +    (with-temp-buffer
 +      (pp (nreverse packages) (current-buffer))
 +      (write-region nil nil "archive-contents"))))
 +
 +(defconst archive--revno-re "[0-9a-f]+")
 +
 +(defun archive-prepare-packages (srcdir)
 +  "Prepare the `packages' directory inside the Git checkout.
 +Expects to be called from within the `packages' directory.
 +\"Prepare\" here is for subsequent construction of the packages and archive,
 +so it is meant to refresh any generated files we may need.
 +Currently only refreshes the ChangeLog files."
 +  (setq srcdir (file-name-as-directory (expand-file-name srcdir)))
 +  (let* ((wit ".changelog-witness")
 +         (prevno (with-temp-buffer
 +                   (ignore-errors (insert-file-contents wit))
 +                   (if (looking-at (concat archive--revno-re "$"))
 +                       (match-string 0)
 +                     (error "Can't find previous revision name"))))
 +         (new-revno
 +          (or (with-temp-buffer
 +                (let ((default-directory srcdir))
 +                  (call-process "git" nil '(t) nil "rev-parse" "HEAD")
 +                  (goto-char (point-min))
 +                  (when (looking-at (concat archive--revno-re "$"))
 +                    (match-string 0))))
 +              (error "Couldn't find the current revision's name")))
 +         (pkgs '()))
 +    (unless (equal prevno new-revno)
 +      (with-temp-buffer
 +        (let ((default-directory srcdir))
 +          (unless (zerop (call-process "git" nil '(t) nil "diff"
 +                                       "--dirstat=cumulative,0"
 +                                       prevno))
 +            (error "Error signaled by git diff --dirstat %d" prevno)))
 +        (goto-char (point-min))
 +        (while (re-search-forward "^[ \t.0-9%]* 
packages/\\([-[:alnum:]]+\\)/$"
 +                                  nil t)
 +          (push (match-string 1) pkgs))))
 +    (let ((default-directory (expand-file-name "packages/")))
 +      (dolist (pkg pkgs)
 +        (condition-case v
 +            (if (file-directory-p pkg)
 +                (archive--make-changelog pkg (expand-file-name "packages/"
 +                                                               srcdir)))
 +          (error (message "Error: %S" v)))))
 +    (write-region new-revno nil wit nil 'quiet)
 +    ;; Also update the ChangeLog of external packages.
 +    (let ((default-directory (expand-file-name "packages/")))
 +      (dolist (dir (directory-files "."))
 +        (and (not (member dir '("." "..")))
 +             (file-directory-p dir)
 +             (let ((index (expand-file-name
 +                           (concat "packages/" dir "/.git/index")
 +                           srcdir))
 +                   (cl (expand-file-name "ChangeLog" dir)))
 +               (and (file-exists-p index)
 +                    (or (not (file-exists-p cl))
 +                        (file-newer-than-file-p index cl))))
 +             (archive--make-changelog
 +              dir (expand-file-name "packages/" srcdir)))))
 +    ))
 +
 +(defun archive--simple-package-p (dir pkg)
 +  "Test whether DIR contains a simple package named PKG.
 +Return a list (SIMPLE VERSION DESCRIPTION REQ), where
 +SIMPLE is non-nil if the package is indeed simple;
 +VERSION is the version string of the simple package;
 +DESCRIPTION is the brief description of the package;
 +REQ is a list of requirements.
 +Otherwise, return nil."
 +  (let* ((pkg-file (expand-file-name (concat pkg "-pkg.el") dir))
 +       (mainfile (expand-file-name (concat pkg ".el") dir))
 +         (files (directory-files dir nil "\\.el\\'"))
 +       version description req)
 +    (setq files (delete (concat pkg "-pkg.el") files))
 +    (setq files (delete (concat pkg "-autoloads.el") files))
 +    (cond
 +     ((and (not (file-exists-p pkg-file))
 +           (file-exists-p mainfile))
 +      (with-temp-buffer
 +      (insert-file-contents mainfile)
 +      (goto-char (point-min))
 +      (if (not (looking-at ";;;.*---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ 
\t]*\\)?$"))
 +            (error "Can't parse first line of %s" mainfile)
 +          (setq description (match-string 1))
 +          (setq version
 +                (or (archive--strip-rcs-id (lm-header "package-version"))
 +                    (archive--strip-rcs-id (lm-header "version"))
 +                    (error "Missing `version' header")))
 +          ;; Grab the other fields, which are not mandatory.
 +          (let ((requires-str (lm-header "package-requires")))
 +            (if requires-str
 +                (setq req (mapcar 'archive--convert-require
 +                                  (car (read-from-string requires-str))))))
 +          (list (= (length files) 1) version description req))))
 +     ((not (file-exists-p pkg-file))
 +      (error "Can find single file nor package desc file in %s" dir)))))
 +
 +(defun archive--process-simple-package (dir pkg vers desc req)
 +  "Deploy the contents of DIR into the archive as a simple package.
 +Rename DIR/PKG.el to PKG-VERS.el, delete DIR, and return the descriptor."
 +  ;; Write DIR/foo.el to foo-VERS.el and delete DIR
 +  (rename-file (expand-file-name (concat pkg ".el") dir)
 +             (concat pkg "-" vers ".el"))
 +  ;; Add the content of the ChangeLog.
 +  (let ((cl (expand-file-name "ChangeLog" dir)))
 +    (with-current-buffer (find-file-noselect (concat pkg "-" vers ".el"))
 +      (goto-char (point-max))
 +      (re-search-backward "^;;;.*ends here")
 +      (re-search-backward "^(provide")
 +      (skip-chars-backward " \t\n")
 +      (insert "\n\n;;;; ChangeLog:\n\n")
 +      (let* ((start (point))
 +             (end (copy-marker start t)))
 +        (insert-file-contents cl)
 +        (goto-char end)
 +        (unless (bolp) (insert "\n"))
 +        (while (progn (forward-line -1) (>= (point) start))
 +          (insert ";; ")))
 +      (set (make-local-variable 'backup-inhibited) t)
 +      (basic-save-buffer)               ;Less chatty than save-buffer.
 +      (kill-buffer)))
 +  (delete-directory dir t)
 +  (cons (intern pkg) (vector (version-to-list vers) req desc 'single)))
 +
 +(defun archive--make-changelog (dir srcdir)
 +  "Export Git log info of DIR into a ChangeLog file."
 +  (message "Refreshing ChangeLog in %S" dir)
 +  (let ((default-directory (file-name-as-directory (expand-file-name dir))))
 +    (with-temp-buffer
 +      (set-buffer-multibyte nil)
 +      (let ((coding-system-for-read 'binary)
 +            (coding-system-for-write 'binary))
 +        (if (file-readable-p "ChangeLog") (insert-file-contents "ChangeLog"))
 +        (let ((old-md5 (md5 (current-buffer))))
 +          (erase-buffer)
 +          (let ((default-directory
 +                  (file-name-as-directory (expand-file-name dir srcdir))))
 +            (call-process "git" nil (current-buffer) nil
 +                          "log" "--date=short"
 +                          "--format=%cd  %aN  <%ae>%n%n%w(80,8,8)%B%n"
 +                          "."))
 +          (tabify (point-min) (point-max))
 +          (goto-char (point-min))
 +          (while (re-search-forward "\n\n\n+" nil t)
 +            (replace-match "\n\n"))
 +          (if (equal old-md5 (md5 (current-buffer)))
 +              (message "ChangeLog's md5 unchanged for %S" dir)
 +            (write-region (point-min) (point-max) "ChangeLog" nil 
'quiet)))))))
 +
 +(defun archive--process-multi-file-package (dir pkg)
 +  "Deploy the contents of DIR into the archive as a multi-file package.
 +Rename DIR/ to PKG-VERS/, and return the descriptor."
 +  (let* ((exp (archive--multi-file-package-def dir pkg))
 +       (vers (nth 2 exp))
 +       (req (mapcar 'archive--convert-require (nth 4 exp))))
 +    (unless (equal (nth 1 exp) pkg)
 +      (error (format "Package name %s doesn't match file name %s"
 +                   (nth 1 exp) pkg)))
 +    (rename-file dir (concat pkg "-" vers))
 +    (cons (intern pkg) (vector (version-to-list vers) req (nth 3 exp) 'tar))))
 +
 +(defun archive--multi-file-package-def (dir pkg)
 +  "Return the `define-package' form in the file DIR/PKG-pkg.el."
 +  (let ((pkg-file (expand-file-name (concat pkg "-pkg.el") dir)))
 +    (with-temp-buffer
 +      (unless (file-exists-p pkg-file)
 +      (error "File not found: %s" pkg-file))
 +      (insert-file-contents pkg-file)
 +      (goto-char (point-min))
 +      (read (current-buffer)))))
 +
 +(defun archive--refresh-pkg-file ()
 +  (let* ((dir (directory-file-name default-directory))
 +         (pkg (file-name-nondirectory dir))
 +         (simple-p (archive--simple-package-p dir pkg)))
 +    (if simple-p
 +        (progn
 +          ;; (message "Refreshing pkg description of %s" pkg)
 +          (apply 'archive--write-pkg-file dir pkg (cdr simple-p)))
 +      ;; (message "Not refreshing pkg description of %s" pkg)
 +      )))
 +
 +(defun archive--write-pkg-file (pkg-dir name version desc requires &rest 
ignored)
 +  (let ((pkg-file (expand-file-name (concat name "-pkg.el") pkg-dir))
 +      (print-level nil)
 +        (print-quoted t)
 +      (print-length nil))
 +    (write-region
 +     (concat (format ";; Generated package description from %s.el\n"
 +                   name)
 +           (prin1-to-string
 +            (list 'define-package
 +                  name
 +                  version
 +                  desc
 +                  (list 'quote
 +                        ;; Turn version lists into string form.
 +                        (mapcar
 +                         (lambda (elt)
 +                           (list (car elt)
 +                                 (package-version-join (cadr elt))))
 +                         requires))))
 +           "\n")
 +     nil
 +     pkg-file)))
 +
 +;;; Make the HTML pages for online browsing.
 +
 +(defun archive--html-header (title)
 +  (format "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">
 +<html>
 +<head>
 +  <title>%s</title>
 +  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
 +</head>
 +<body>
 +<h1 align=\"center\">%s</h1>\n"
 +          title title))
 +
 +(defun archive--html-bytes-format (bytes) ;Aka memory-usage-format.
 +  (setq bytes (/ bytes 1024.0))
 +  (let ((units '(;; "B"
 +                 "kB" "MB" "GB" "TB")))
 +    (while (>= bytes 1024)
 +      (setq bytes (/ bytes 1024.0))
 +      (setq units (cdr units)))
 +    (cond
 +     ;; ((integerp bytes) (format "%4d%s" bytes (car units)))
 +     ((>= bytes 100) (format "%4.0f%s" bytes (car units)))
 +     ((>= bytes 10) (format "%4.1f%s" bytes (car units)))
 +     (t (format "%4.2f%s" bytes (car units))))))
 +
 +(defun archive--get-prop (prop name srcdir mainsrcfile)
 +  (let ((kprop (intern (format ":%s" (downcase prop)))))
 +    (or
 +     (let ((pkgdescfile (expand-file-name (format "%s-pkg.el" name)
 +                                          srcdir)))
 +       (when (file-readable-p pkgdescfile)
 +         (with-temp-buffer
 +           (insert-file-contents pkgdescfile)
 +           (let ((desc (read (current-buffer))))
 +             (plist-get (cdr desc) kprop)))))
 +     (when (file-readable-p mainsrcfile)
 +       (with-temp-buffer
 +         (insert-file-contents mainsrcfile)
 +         (lm-header prop))))))
 +
 +(defun archive--get-section (hsection fsection srcdir mainsrcfile)
 +  (when (consp fsection)
 +    (while (cdr-safe fsection)
 +      (setq fsection
 +            (if (file-readable-p (expand-file-name (car fsection) srcdir))
 +                (car fsection)
 +              (cdr fsection))))
 +    (when (consp fsection) (setq fsection (car fsection))))
 +  (cond
 +   ((file-readable-p (expand-file-name fsection srcdir))
 +    (with-temp-buffer
 +      (insert-file-contents (expand-file-name fsection srcdir))
 +      (buffer-string)))
 +   ((file-readable-p mainsrcfile)
 +    (with-temp-buffer
 +      (insert-file-contents mainsrcfile)
 +      (let ((start (lm-section-start hsection)))
 +        (when start
 +          (insert
 +           (prog1
 +               (buffer-substring start (lm-section-end hsection))
 +             (erase-buffer)))
 +          (emacs-lisp-mode)
 +          (goto-char (point-min))
 +          (delete-region (point) (line-beginning-position 2))
 +          (uncomment-region (point-min) (point-max))
 +          (when (looking-at "^\\([ \t]*\n\\)+")
 +            (replace-match ""))
 +          (goto-char (point-max))
 +          (skip-chars-backward " \t\n")
 +          (delete-region (point) (point-max))
 +          (buffer-string)))))))
 +
 +(defun archive--quote (txt)
 +  (replace-regexp-in-string "<" "&lt;"
 +                            (replace-regexp-in-string "&" "&amp;" txt)))
 +
 +(defun archive--insert-repolinks (name srcdir mainsrcfile)
 +  (let ((url (archive--get-prop "URL" name srcdir mainsrcfile)))
 +    (if url
 +        (insert (format "<p>Origin: <a href=%S>%s</a></p>\n"
 +                        url (archive--quote url)))
 +      (let* ((externals
 +              (with-temp-buffer
 +                (insert-file-contents
 +                 (expand-file-name "../../../elpa/externals-list" srcdir))
 +                (read (current-buffer))))
 +             (external (eq :external (nth 1 (assoc name externals))))
 +             (git-sv "http://git.savannah.gnu.org/";)
 +             (urls (if external
 +                       '("cgit/emacs/elpa.git/?h=externals/"
 +                         
"gitweb/?p=emacs/elpa.git;a=shortlog;h=refs/heads/externals/")
 +                     '("cgit/emacs/elpa.git/tree/packages/"
 +                       "gitweb/?p=emacs/elpa.git;a=tree;f=packages/"))))
 +        (insert (format
 +                 (concat "<p>Browse repository: <a href=%S>%s</a>"
 +                         " or <a href=%S>%s</a></p>\n")
 +                 (concat git-sv (nth 0 urls) name)
 +                 'CGit
 +                 (concat git-sv (nth 1 urls) name)
 +                 'Gitweb))))))
 +
 +(defun archive--html-make-pkg (pkg files)
 +  (let* ((name (symbol-name (car pkg)))
 +         (latest (package-version-join (aref (cdr pkg) 0)))
 +         (srcdir (expand-file-name name "../../build/packages"))
 +         (mainsrcfile (expand-file-name (format "%s.el" name) srcdir))
 +         (desc (aref (cdr pkg) 2)))
 +    (with-temp-buffer
 +      (insert (archive--html-header (format "GNU ELPA - %s" name)))
 +      (insert (format "<p>Description: %s</p>\n" (archive--quote desc)))
 +      (let* ((file (cdr (assoc latest files)))
 +             (attrs (file-attributes file)))
 +        (insert (format "<p>Latest: <a href=%S>%s</a>, %s, %s</p>\n"
 +                        file (archive--quote file)
 +                        (format-time-string "%Y-%b-%d" (nth 5 attrs))
 +                        (archive--html-bytes-format (nth 7 attrs)))))
 +      (let ((maint (archive--get-prop "Maintainer" name srcdir mainsrcfile)))
 +        (when maint
 +          (insert (format "<p>Maintainer: %s</p>\n" (archive--quote maint)))))
 +      (archive--insert-repolinks name srcdir mainsrcfile)
-       (let ((readme (archive--get-section "Commentary"
-                                           '("README" "README.rst" "README.md"
-                                             "README.org")
-                                           srcdir mainsrcfile)))
-         (when readme
-           (write-region readme nil (concat name "-readme.txt"))
-           (insert "<h2>Full description</h2><pre>\n" (archive--quote readme)
++      (let ((rm (archive--get-section
++                 "Commentary" '("README" "README.rst" "README.md" 
"README.org")
++                 srcdir mainsrcfile)))
++        (when rm
++          (write-region rm nil (concat name "-readme.txt"))
++          (insert "<h2>Full description</h2><pre>\n" (archive--quote rm)
 +                  "\n</pre>\n")))
 +      (unless (< (length files) 2)
 +        (insert (format "<h2>Old versions</h2><table cellpadding=\"3\" 
border=\"1\">\n"))
 +        (dolist (file files)
 +          (unless (equal (pop file) latest)
 +            (let ((attrs (file-attributes file)))
 +              (insert (format "<tr><td><a 
href=%S>%s</a></td><td>%s</td><td>%s</td>\n"
 +                              file (archive--quote file)
 +                              (format-time-string "%Y-%b-%d" (nth 5 attrs))
 +                              (archive--html-bytes-format (nth 7 attrs)))))))
 +        (insert "</table>\n"))
-       (let ((news (archive--get-section "News" "NEWS" srcdir mainsrcfile)))
++      (let ((news (archive--get-section
++                   "News" '("NEWS" "NEWS.rst" "NEWS.md" "NEWS.org")
++                   srcdir mainsrcfile)))
 +        (when news
 +          (insert "<h2>News</h2><pre>\n" (archive--quote news) "\n</pre>\n")))
 +      (insert "</body>\n")
 +      (write-region (point-min) (point-max) (concat name ".html")))))
 +
 +(defun archive--html-make-index (pkgs)
 +  (with-temp-buffer
 +    (insert (archive--html-header "GNU ELPA Packages"))
 +    (insert "<table cellpadding=\"3\" border=\"1\">\n")
 +    (insert "<tr><th>Package</th><th>Version</th><th>Description</th></tr>\n")
 +    (dolist (pkg pkgs)
 +      (insert (format "<tr><td><a 
href=\"%s.html\">%s</a></td><td>%s</td><td>%s</td></tr>\n"
 +                      (car pkg) (car pkg)
 +                      (package-version-join (aref (cdr pkg) 0))
 +                      (aref (cdr pkg) 2))))
 +    (insert "</table></body>\n")
 +    (write-region (point-min) (point-max) "index.html")))
 +
 +(defun batch-html-make-index ()
 +  (let ((packages (make-hash-table :test #'equal))
 +        (archive-contents
 +         (with-temp-buffer
 +           (insert-file-contents "archive-contents")
 +           (goto-char (point-min))
 +           ;; Skip the first element which is a version number.
 +           (cdr (read (current-buffer))))))
 +    (dolist (file (directory-files default-directory nil))
 +      (cond
 +       ((member file '("." ".." "elpa.rss" "index.html" "archive-contents")))
 +       ((string-match "\\.html\\'" file))
 +       ((string-match "-readme\\.txt\\'" file)
 +        (let ((name (substring file 0 (match-beginning 0))))
 +          (puthash name (gethash name packages) packages)))
 +       ((string-match "-\\([0-9][^-]*\\)\\.\\(tar\\|el\\)\\'" file)
 +        (let ((name (substring file 0 (match-beginning 0)))
 +              (version (match-string 1 file)))
 +          (push (cons version file) (gethash name packages))))
 +       (t (message "Unknown file %S" file))))
 +    (dolist (pkg archive-contents)
 +      (archive--html-make-pkg pkg (gethash (symbol-name (car pkg)) packages)))
 +    ;; FIXME: Add (old?) packages that are in `packages' but not in
 +    ;; archive-contents.
 +    (archive--html-make-index archive-contents)))
 +
 +;;; Maintain external packages.
 +
 +(defconst archive--elpa-git-url "git://git.sv.gnu.org/emacs/elpa")
 +
 +(defun archive-add/remove/update-externals ()
 +  (let ((exts (with-current-buffer (find-file-noselect "externals-list")
 +                (goto-char (point-min))
 +                (read (current-buffer)))))
 +    (let ((default-directory (expand-file-name "packages/")))
 +      ;; Remove "old/odd" externals.
 +      (dolist (dir (directory-files "."))
 +        (cond
 +         ((member dir '("." "..")) nil)
 +         ((assoc dir exts) nil)
 +         ((file-directory-p (expand-file-name (format "%s/.git" dir)))
 +          (let ((status
 +                 (with-temp-buffer
 +                   (let ((default-directory (file-name-as-directory
 +                                             (expand-file-name dir))))
 +                     (call-process "git" nil t nil "status" "--porcelain")
 +                     (buffer-string)))))
 +            (if (zerop (length status))
 +                (progn (delete-directory dir 'recursive t)
 +                       (message "Deleted all of %s" dir))
 +              (message "Keeping leftover unclean %s:\n%s" dir status))))))
 +      (pcase-dolist (`(,dir ,kind ,_url) exts)
 +        (cond
 +         ((eq kind :subtree) nil)       ;Nothing to do.
 +         ((not (eq kind :external))
 +          (message "Unknown external package kind `%S' for %s" kind dir))
 +         ((not (file-exists-p dir))
 +          (let* ((branch (concat "externals/" dir))
 +                 (output
 +                  (with-temp-buffer
 +                    ;; FIXME: Use git-new-workdir!
 +                    (call-process "git" nil t nil "clone"
 +                                  "--reference" ".." "--branch" branch
 +                                  archive--elpa-git-url dir)
 +                    (buffer-string))))
 +            (message "Cloning branch %s:\n%s" dir output)))
 +         ((not (file-directory-p (concat dir "/.git")))
 +          (message "%s is in the way of an external, please remove!" dir))
 +         (t
 +          (let ((default-directory (file-name-as-directory
 +                                    (expand-file-name dir))))
 +            (with-temp-buffer
 +              (message "Running git pull in %S" default-directory)
 +              (call-process "git" nil t nil "pull")
 +              (message "Updated %s:%s" dir (buffer-string))))
 +          ))))))
 +
 +(provide 'archive-contents)
 +;;; archive-contents.el ends here
diff --cc packages/company/.gitignore
index 0000000,2ecd291..2ecd291
mode 000000,100644..100644
--- a/packages/company/.gitignore
+++ b/packages/company/.gitignore
diff --cc packages/company/.travis.yml
index 0000000,cdf55d1..cdf55d1
mode 000000,100644..100644
--- a/packages/company/.travis.yml
+++ b/packages/company/.travis.yml
diff --cc packages/company/Makefile
index 0000000,f11b04e..f11b04e
mode 000000,100644..100644
--- a/packages/company/Makefile
+++ b/packages/company/Makefile
diff --cc packages/company/NEWS.md
index 0000000,64860ba..64860ba
mode 000000,100644..100644
--- a/packages/company/NEWS.md
+++ b/packages/company/NEWS.md
diff --cc packages/company/README.md
index 0000000,4f79bbc..4f79bbc
mode 000000,100644..100644
--- a/packages/company/README.md
+++ b/packages/company/README.md

commit fae643a95ed3ba2cefbe70c94d16da7b17877dca
Merge: de72888 4c4829d
Author: Stefan Monnier <address@hidden>
Date:   Wed Aug 14 23:39:50 2013 -0400

    Mark merge point of ack-el.

diff --cc packages/ack/README.rst
index 0000000,9d4e14f..9d4e14f
mode 000000,100644..100644
--- a/packages/ack/README.rst
+++ b/packages/ack/README.rst
diff --cc packages/ack/ack.el
index e749355,01529d7..f7a91d0
--- a/packages/ack/ack.el
+++ b/packages/ack/ack.el
@@@ -1,4 -1,4 +1,4 @@@
--;;; ack.el --- interface to ack-like tools   -*- lexical-binding: t; -*-
++;;; ack.el --- Interface to ack-like source code search tools   -*- 
lexical-binding: t; -*-
  
  ;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
  

commit de7288845c1310f3e6f79b8e5cff7415a894c748
Author: Stefan Monnier <address@hidden>
Date:   Wed Aug 14 23:28:31 2013 -0400

    Use README.{rst,md,org}; Auto-generate foo-pkg.el.

diff --git a/admin/archive-contents.el b/admin/archive-contents.el
index fcc7071..072d03f 100644
--- a/admin/archive-contents.el
+++ b/admin/archive-contents.el
@@ -76,9 +76,10 @@ Delete backup files also."
              (archive--delete-elc-files dir)
              ;; Test whether this is a simple or multi-file package.
              (setq simple-p (archive--simple-package-p dir pkg))
-             (push (if simple-p
+             (push (if (car simple-p)
                        (apply #'archive--process-simple-package
-                              dir pkg simple-p)
+                              dir pkg (cdr simple-p))
+                      (apply 'archive--write-pkg-file dir pkg (cdr simple-p))
                      (archive--process-multi-file-package dir pkg))
                    packages)))
        (error (error "Error in %s: %S" dir v))))
@@ -147,24 +148,20 @@ Currently only refreshes the ChangeLog files."
 
 (defun archive--simple-package-p (dir pkg)
   "Test whether DIR contains a simple package named PKG.
-If so, return a list (VERSION DESCRIPTION REQ), where
-VERSION is the version string of the simple package, DESCRIPTION
-is the brief description of the package, REQ is a list of
-requirements.
+Return a list (SIMPLE VERSION DESCRIPTION REQ), where
+SIMPLE is non-nil if the package is indeed simple;
+VERSION is the version string of the simple package;
+DESCRIPTION is the brief description of the package;
+REQ is a list of requirements.
 Otherwise, return nil."
   (let* ((pkg-file (expand-file-name (concat pkg "-pkg.el") dir))
         (mainfile (expand-file-name (concat pkg ".el") dir))
-         (files (directory-files dir nil archive-re-no-dot))
+         (files (directory-files dir nil "\\.el\\'"))
         version description req)
-    (dolist (file (prog1 files (setq files ())))
-      (unless (string-match "\\(?:\\.elc\\|~\\)\\'" file)
-        (push file files)))
     (setq files (delete (concat pkg "-pkg.el") files))
     (setq files (delete (concat pkg "-autoloads.el") files))
-    (setq files (delete "ChangeLog" files))
     (cond
-     ((and (or (not (file-exists-p pkg-file))
-               (= (length files) 1))
+     ((and (not (file-exists-p pkg-file))
            (file-exists-p mainfile))
       (with-temp-buffer
        (insert-file-contents mainfile)
@@ -181,7 +178,7 @@ Otherwise, return nil."
             (if requires-str
                 (setq req (mapcar 'archive--convert-require
                                   (car (read-from-string requires-str))))))
-          (list version description req))))
+          (list (= (length files) 1) version description req))))
      ((not (file-exists-p pkg-file))
       (error "Can find single file nor package desc file in %s" dir)))))
 
@@ -266,7 +263,7 @@ Rename DIR/ to PKG-VERS/, and return the descriptor."
     (if simple-p
         (progn
           ;; (message "Refreshing pkg description of %s" pkg)
-          (apply 'archive--write-pkg-file dir pkg simple-p))
+          (apply 'archive--write-pkg-file dir pkg (cdr simple-p)))
       ;; (message "Not refreshing pkg description of %s" pkg)
       )))
 
@@ -336,6 +333,13 @@ Rename DIR/ to PKG-VERS/, and return the descriptor."
          (lm-header prop))))))
 
 (defun archive--get-section (hsection fsection srcdir mainsrcfile)
+  (when (consp fsection)
+    (while (cdr-safe fsection)
+      (setq fsection
+            (if (file-readable-p (expand-file-name (car fsection) srcdir))
+                (car fsection)
+              (cdr fsection))))
+    (when (consp fsection) (setq fsection (car fsection))))
   (cond
    ((file-readable-p (expand-file-name fsection srcdir))
     (with-temp-buffer
@@ -409,7 +413,10 @@ Rename DIR/ to PKG-VERS/, and return the descriptor."
         (when maint
           (insert (format "<p>Maintainer: %s</p>\n" (archive--quote maint)))))
       (archive--insert-repolinks name srcdir mainsrcfile)
-      (let ((readme (archive--get-section "Commentary" "README" srcdir 
mainsrcfile)))
+      (let ((readme (archive--get-section "Commentary"
+                                          '("README" "README.rst" "README.md"
+                                            "README.org")
+                                          srcdir mainsrcfile)))
         (when readme
           (write-region readme nil (concat name "-readme.txt"))
           (insert "<h2>Full description</h2><pre>\n" (archive--quote readme)
@@ -471,7 +478,7 @@ Rename DIR/ to PKG-VERS/, and return the descriptor."
 
 ;;; Maintain external packages.
 
-(defconst archive--elpa-git-url "git+ssh://git.sv.gnu.org/srv/git/emacs/elpa")
+(defconst archive--elpa-git-url "git://git.sv.gnu.org/emacs/elpa")
 
 (defun archive-add/remove/update-externals ()
   (let ((exts (with-current-buffer (find-file-noselect "externals-list")
diff --git a/admin/update-archive.sh b/admin/update-archive.sh
index 91090ac..fb7b91d 100755
--- a/admin/update-archive.sh
+++ b/admin/update-archive.sh
@@ -40,10 +40,15 @@ cd ../elpa
 # Fetch changes.
 git pull || signal_error "git pull failed"
 
+# Remember we're inside the "elpa" branch which we don't want to trust,
+# So always refer to the makefile and admins files from $builddir".
+
 # Setup and update externals.
-make externals
+emacs --batch -l "$buildir/admin/archive-contents.el" \
+      -f archive-add/remove/update-externals
 
-make check_copyrights || signal_error "check_copyright failed"
+make -f "$buildir/GNUmakefile" check_copyrights ||
+    signal_error "check_copyright failed"
 
 cd "$buildir"
 

commit 4faa2623a68e90c3b817bf83f2ff1785b85684d6
Merge: adba6bf eb912a1
Author: Stefan Monnier <address@hidden>
Date:   Wed Aug 14 23:25:46 2013 -0400

    Mark merge point of coffee-mode.

diff --cc externals-list
index e2b7504,0000000..ef40b34
mode 100644,000000..100644
--- a/externals-list
+++ b/externals-list
@@@ -1,36 -1,0 +1,35 @@@
 +;; -*- emacs-lisp -*-
 +
 +;; List of packages that are maintained externally.
 +;; The list is made of elements of the form (NAME KIND URL).
 +;;
 +;; Where NAME is the name of the package;
 +;;
 +;; KIND can be one of:
 +;;  :subtree  = a "git subtree" in the `master' branch.
 +;;  :external = kept in a separate `externals/<name>' branch.
 +;;
 +;; And URL is the URL of the remote git repository that we want to track.
 +;; It can be nil, in which case we don't track anything (useless for
 +;; :subtree, but not for :external).
 +
 +;; The FIXMEs indicate that the branch can't be merged as is because it needs
 +;; some manual intervention (typically, because the two branches have
 +;; diverged).
 +
 +(("ack"                       :subtree "https://github.com/leoliu/ack-el";)
-  ;; In need of serious manual sync as well.
 + ;;FIXME:("auctex"    :subtree "git://git.sv.gnu.org/auctex.git")
 + ("coffee-mode"               :subtree 
"https://github.com/defunkt/coffee-mode";)
 + ("company"           :subtree 
"https://github.com/company-mode/company-mode.git";)
 + ("dismal"            :external nil)
 + ("eldoc-eval"                :subtree 
"https://github.com/thierryvolpiatto/eldoc-eval.git";)
 + ("enwc"              :subtree 
"bzr::bzr://bzr.savannah.nongnu.org/enwc/trunk")
 + ("f90-interface-browser" :subtree "http://github.com/wence-/f90-iface";)
 + ("ggtags"            :subtree "https://github.com/leoliu/ggtags";)
 + ("ioccur"            :subtree 
"https://github.com/thierryvolpiatto/ioccur.git";)
 + ("js2-mode"          :subtree "https://github.com/mooz/js2-mode.git";)
 + ;;FIXME:("org"               :external ??) ;; Need to introduce snapshots!!
 + ;;FIXME:("vlf"               :subtree ??)
 + ("websocket"         :subtree 
"https://github.com/ahyatt/emacs-websocket.git";)
 + ;;FIXME:("yasnippet" :subtree 
"https://github.com/capitaomorte/yasnippet.git";)
 + )
diff --cc packages/coffee-mode/coffee-mode.el
index 4420ab9,87a95e7..427c047
--- a/packages/coffee-mode/coffee-mode.el
+++ b/packages/coffee-mode/coffee-mode.el
@@@ -24,55 -25,34 +24,68 @@@
  
  ;;; Commentary
  
 -;; For commentary please see the README.md or
 -;; http://github.com/defunkt/coffee-mode#readme
 +;; CoffeeScript mode is an Emacs major mode for [CoffeeScript][cs],
 +;; unfancy JavaScript.  It provides syntax highlighting, indentation
 +;; support, imenu support, a menu bar, and a few cute commands.
  
 -;;; Installation
 +;; Installing this package enables CoffeeScript mode for file named
 +;; *.coffee and Cakefile.
  
 -;; In your shell:
 +;; Commands:
  
 -;;     $ cd ~/.emacs.d/vendor
 -;;     $ git clone git://github.com/defunkt/coffee-mode.git
 -
 -;; In your emacs config:
 -
 -;;     (add-to-list 'load-path "~/.emacs.d/vendor/coffee-mode")
 -;;     (require 'coffee-mode)
 +;; M-x coffee-compile-file compiles the current file as a JavaScript
 +;; file.  Operating on "basic.coffee" and running this command will
 +;; save a "basic.js" in the same directory.  Subsequent runs will
 +;; overwrite the file.
 +;;
 +;; If there are compilation errors and we the compiler have returned a
 +;; line number to us for the first error, the point is moved to that
 +;; line, so you can investigate.  If this annoys you, you can set
 +;; `coffee-compile-jump-to-error` to `nil`.
 +;;
 +;; M-x coffee-compile-buffer compiles the current buffer to JavaScript
 +;; using the command specified by the `coffee-command` variable, and
 +;; opens the contents in a new buffer using the mode configured for
 +;; ".js" files.
 +;;
 +;; M-x coffee-compile-region compiles the selected region to
 +;; JavaScript using the same configuration variables as
 +;; `coffee-compile-buffer`.
 +;;
 +;; `C-c C-o C-s' (coffee-cos-mode) toggles a minor mode implementing
 +;; "compile-on-save" behavior.
 +;;
 +;; M-x coffee-repl starts a repl via `coffee-command` in a new buffer.
  
 -;;; Thanks
 +;; Options:
 +;;
 +;; `coffee-tab-width' - Tab width to use when indenting.
 +;; `coffee-command'   - CoffeeScript command for evaluating code.
 +;;                      Must be in your path.
 +;; `coffee-args-repl' - Command line arguments for `coffee-command'
 +;;                      when starting a REPL.
 +;; `coffee-args-compile'          - Arguments for `coffee-command'
 +;;                                  when compiling a file.
 +;; `coffee-compiled-buffer-name'  - Name of the scratch buffer used
 +;;                                  when compiling CoffeeScript.
 +;; `coffee-compile-jump-to-error' - Whether to jump to the first error
 +;;                                  if compilation fails.
 +
 +;; Please file bugs at <http://github.com/defunkt/coffee-mode/issues>
 +
++;; Thanks:
+ 
+ ;; Major thanks to http://xahlee.org/emacs/elisp_syntax_coloring.html
+ ;; the instructions.
+ 
+ ;; Also thanks to Jason Blevins's markdown-mode.el and Steve Yegge's
+ ;; js2-mode for guidance.
+ 
+ ;; TODO:
+ ;; - Execute {buffer,region,line} and show output in new buffer
+ ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
+ ;; - mirror-mode - close brackets and parens automatically
+ 
  ;;; Code:
  
  (require 'comint)

commit 06955397d6103651fc01022dc45174b72b4260dc
Author: Stefan Monnier <address@hidden>
Date:   Tue Aug 13 16:35:49 2013 +0200

    Merge with ELPA
    (eldoc-display-message-no-interference-p): Turn it into an advice.elpa
    (eldoc-active-minibuffers-list): Store buffers rather than buffer names.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index cace999..5be33e3 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -1,6 +1,6 @@
 ;;; eldoc-eval.el --- Enable eldoc support when minibuffer is in use.
 
-;; Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
 
 ;; Author: Thierry Volpiatto <address@hidden>
 ;; Version: 0.1
@@ -45,6 +45,12 @@
 ;;; Code:
 (require 'eldoc)
 
+;; FIXME: This has no autoloads and (require 'eldoc-eval) will change Emacs's
+;; behavior, against usual conventions.  The fix is to define
+;; eldoc-in-minibuffer as a (global) minor mode, then autoload it.  So the
+;; default value will be nil, and the user can enable it with
+;; (eldoc-in-minibuffer 1) or by customizing eldoc-in-minibuffer, rather than
+;; by adding (require 'eldoc-eval) in her .emacs.
 
 ;;; Minibuffer support.
 ;;  Enable displaying eldoc info in something else
@@ -84,14 +90,17 @@ Should take one arg: the string to display"
 (when (boundp 'eldoc-message-function)
   (setq eldoc-message-function 'message)
 
-  (defun eldoc-display-message-no-interference-p ()
+  (defadvice eldoc-display-message-no-interference-p
+      (around eldoc-eval activate)
+    (if (not eldoc-in-minibuffer)
+        ad-do-it
     (and eldoc-mode
          (not executing-kbd-macro)
          (not (and (boundp 'edebug-active) edebug-active))
          ;; Having this mode operate in an active minibuffer/echo area causes
          ;; interference with what's going on there.
          (not cursor-in-echo-area)
-         (not (eq (selected-window) (minibuffer-window))))))
+           (not (eq (selected-window) (minibuffer-window)))))))
 
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil
@@ -103,7 +112,7 @@ Should take one arg: the string to display"
 This function is called by each minibuffer started with eldoc support.
 See `with-eldoc-in-minibuffer'."
   (with-selected-window (minibuffer-window)
-    (push (buffer-name) eldoc-active-minibuffers-list)))
+    (push (current-buffer) eldoc-active-minibuffers-list)))
 
 (defmacro with-eldoc-in-minibuffer (&rest body)
   "Enable eldoc support for minibuffer input that runs in BODY."
@@ -166,7 +175,7 @@ See `with-eldoc-in-minibuffer'."
 
 (defun eldoc-mode-in-minibuffer ()
   "Show eldoc for current minibuffer input."
-  (let ((buf (buffer-name (window-buffer (active-minibuffer-window)))))
+  (let ((buf (window-buffer (active-minibuffer-window))))
     ;; If this minibuffer have been started with
     ;;`with-eldoc-in-minibuffer' give it eldoc support
     ;; and update mode-line, otherwise do nothing.
@@ -193,6 +202,9 @@ See `with-eldoc-in-minibuffer'."
     (call-interactively eval-preferred-function)))
 
 ;; Bind it to `M-:'.
+
+;; FIXME: Turn eldoc-in-minibuffer into a global minor mode, and place this
+;; binding in its keymap.
 (global-set-key [remap eval-expression] 'eval-expression-with-eldoc)
 
 

commit fb883784a1c773b4a1e43d2aff7658b9129eff00
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 12 09:27:54 2013 +0200

    * eldoc-eval.el: Merge docstring and minors changes from ELPA version.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index 2879caf..cace999 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -1,8 +1,9 @@
-;;; eldoc-eval.el --- Show eldoc when using M-:
+;;; eldoc-eval.el --- Enable eldoc support when minibuffer is in use.
 
-;; Copyright (C) 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2011, 2012 Free Software Foundation, Inc.
 
 ;; Author: Thierry Volpiatto <address@hidden>
+;; Version: 0.1
 
 ;; This file is part of GNU Emacs.
 
@@ -20,11 +21,31 @@
 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
+;;
+;; This package enables eldoc support when minibuffer is in use.
+;;
+;; Eldoc info is shown by default in mode-line,
+;; but you can have eldoc info somewhere else by setting
+;; `eldoc-in-minibuffer-show-fn' to another function (e.g `tooltip-show').
+;;
+;; By default with this package `M-:' will use `pp-eval-expression'
+;; instead of `eval-expression'; you can change that by setting
+;; `eval-preferred-function'.
+;;
+;; It also provides a convenient macro to enable eldoc support
+;; in your own functions using minibuffer or in your defadvices,
+;; that is `with-eldoc-in-minibuffer'.
+;;
+;; Users of own minibuffer frame will have to set
+;; `eldoc-in-minibuffer-own-frame-p' to non-nil.
+;;
+;; You can turn off eldoc support in minibuffer any time
+;; by setting `eldoc-in-minibuffer' to nil.
 
 ;;; Code:
-
 (require 'eldoc)
 
+
 ;;; Minibuffer support.
 ;;  Enable displaying eldoc info in something else
 ;;  Than minibuffer when this one is in use.
@@ -45,13 +66,13 @@ Should take one arg: the string to display"
   :group 'eldoc
   :type 'number)
 
-(defcustom eldoc-eval-prefered-function 'pp-eval-expression
-  "Prefered function to use with `M-:'."
+(defcustom eval-preferred-function 'pp-eval-expression
+  "Preferred function to use with `M-:'."
   :group 'lisp
   :type 'function)
 
 (defcustom  eldoc-in-minibuffer-own-frame-p nil
-  "Whether minibuffer have own frame or not."
+  "Whether minibuffer has its own frame or not."
   :group 'lisp
   :type 'boolean)
 
@@ -74,7 +95,7 @@ Should take one arg: the string to display"
 
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil
-  "Store actives minibuffers with eldoc enabled.")
+  "List of active minibuffers with eldoc enabled.")
 (defvar eldoc-mode-line-rolling-flag nil)
 
 (defun eldoc-store-minibuffer ()
@@ -85,7 +106,7 @@ See `with-eldoc-in-minibuffer'."
     (push (buffer-name) eldoc-active-minibuffers-list)))
 
 (defmacro with-eldoc-in-minibuffer (&rest body)
-  "Enable eldoc support for minibuffer input that run in BODY."
+  "Enable eldoc support for minibuffer input that runs in BODY."
   (declare (indent 0) (debug t))
   `(let ((timer (and eldoc-in-minibuffer
                      (run-with-idle-timer
@@ -98,21 +119,21 @@ See `with-eldoc-in-minibuffer'."
              'eldoc-store-minibuffer
            ,@body)
        (and timer (cancel-timer timer))
-       ;; Each time a minibuffer exit or abort
-       ;; his buffer is removed from stack,
+       ;; Each time a minibuffer exits or aborts
+       ;; its buffer is removed from stack,
        ;; assuming we can only exit the active minibuffer
        ;; on top of stack.
        (setq eldoc-active-minibuffers-list
              (cdr eldoc-active-minibuffers-list)))))
 
 (defun eldoc-current-buffer ()
-  "The `current-buffer' before activating minibuffer."
+  "Return the current buffer prior to activating the minibuffer."
   (with-selected-frame (last-nonminibuffer-frame)
     (window-buffer
      (cond (eldoc-in-minibuffer-own-frame-p
             (selected-window))
            ((fboundp 'window-in-direction)
-            (window-in-direction 
+            (window-in-direction
              'above (minibuffer-window)))
            (t (minibuffer-selected-window))))))
 
@@ -169,7 +190,7 @@ See `with-eldoc-in-minibuffer'."
   "Eval expression with eldoc support in mode-line."
   (interactive)
   (with-eldoc-in-minibuffer
-    (call-interactively eldoc-eval-prefered-function)))
+    (call-interactively eval-preferred-function)))
 
 ;; Bind it to `M-:'.
 (global-set-key [remap eval-expression] 'eval-expression-with-eldoc)

commit 28daa752f9f5578f989985ab3de02a82792c66ef
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 3 14:09:26 2013 -0400

    Syncing to the version now in emacs ELPA repository.
    
    These changes were authored by Stefan Monnier in commits:
    
    address@hidden
    * packages/websocket: Cleanup copyright and code.
    
    and
    
    address@hidden
    * packages/websocket/websocket.el: Fix version number.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index a87d021..af1a4ee 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -1,4 +1,22 @@
-;; Simple functional testing
+;;; websocket-functional-test.el --- Simple functional testing
+
+;; Copyright (c) 2013  Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
 ;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
 ;;
 ;; Note: this functional tests requires that you have python with the
diff --git a/websocket-test.el b/websocket-test.el
index c06d7cf..3cc51f9 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -1,13 +1,13 @@
-;; websocket-test.el --- Unit tests for the websocket layer
+;;; websocket-test.el --- Unit tests for the websocket layer
 
-;; Copyright (c) 2010 Andrew Hyatt
+;; Copyright (c) 2013  Free Software Foundation, Inc.
 ;;
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2 of the
+;; published by the Free Software Foundation; either version 3 of the
 ;; License, or (at your option) any later version.
 ;;
 ;; This program is distributed in the hope that it will be useful, but
@@ -16,9 +16,7 @@
 ;; General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, write to the Free Software
-;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;; This defines and runs ert unit tests.  You can download ert from:
diff --git a/websocket.el b/websocket.el
index ce6249b..7ea9c93 100644
--- a/websocket.el
+++ b/websocket.el
@@ -1,15 +1,15 @@
 ;;; websocket.el --- Emacs WebSocket client and server
 
-;; Copyright (c) 2010 Andrew Hyatt
-;;
+;; Copyright (c) 2013  Free Software Foundation, Inc.
+
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication, Websocket, Server
-;; Version: 1.01
+;; Version: 1.1
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2 of the
+;; published by the Free Software Foundation; either version 3 of the
 ;; License, or (at your option) any later version.
 ;;
 ;; This program is distributed in the hope that it will be useful, but
@@ -18,16 +18,14 @@
 ;; General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, write to the Free Software
-;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;; This implements RFC 6455, which can be found at
 ;; http://tools.ietf.org/html/rfc6455.
 ;;
-;; This library contains code to connect emacs as a client to a
-;; websocket server, and for emacs to act as a server for websocket
+;; This library contains code to connect Emacs as a client to a
+;; websocket server, and for Emacs to act as a server for websocket
 ;; connections.
 ;;
 ;; Websockets clients are created by calling `websocket-open', which
@@ -101,7 +99,7 @@ same for the protocols.
   accept-string
   (inflight-input nil))
 
-(defvar websocket-version "1.01"
+(defvar websocket-version "1.1"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil
@@ -122,7 +120,7 @@ communicate with unmasked clients.")
   "If true, when an error happens in a client callback, invoke the debugger.
 Having this on can cause issues with missing frames if the debugger is
 exited by quitting instead of continuing, so it's best to have this set
-to `nil' unless it is especially needed.")
+to nil unless it is especially needed.")
 
 (defmacro websocket-document-function (function docstring)
   "Document FUNCTION with DOCSTRING.  Use this for defstruct accessor etc."
@@ -212,7 +210,7 @@ approximately 537M long."
                 "Frame value found too large to parse!")))
     ;; n is not 8
     (bindat-get-field
-     (condition-case err
+     (condition-case _
          (bindat-unpack
           `((:val
              ,(cond ((= n 1) 'u8)
@@ -364,8 +362,8 @@ the frame finishes.  If the frame is not completed, return 
NIL."
        :completep (> fin 0)))))
 
 (defun websocket-format-error (err)
-  "Format an error message like command level does. ERR should be
-a cons of error symbol and error data."
+  "Format an error message like command level does.
+ERR should be a cons of error symbol and error data."
 
   ;; Formatting code adapted from `edebug-report-error'
   (concat (or (get (car err) 'error-message)
@@ -375,7 +373,7 @@ a cons of error symbol and error data."
                     (mapconcat #'prin1-to-string
                                (cdr err) ", ")))))
 
-(defun websocket-default-error-handler (websocket type err)
+(defun websocket-default-error-handler (_websocket type err)
   "The default error handler used to handle errors in callbacks."
   (display-warning 'websocket
                    (format "in callback `%S': %s"
@@ -418,11 +416,11 @@ a cons of error symbol and error data."
      "The frame being sent is too large for this emacs to handle")
 
 (defun websocket-intersect (a b)
-  "Simple list intersection, should function like common lisp's 
`intersection'."
+  "Simple list intersection, should function like Common Lisp's 
`intersection'."
   (let ((result))
     (dolist (elem a (nreverse result))
       (when (member elem b)
-        (add-to-list 'result elem)))))
+        (push elem result)))))
 
 (defun websocket-get-debug-buffer-create (websocket)
   "Get or create the buffer corresponding to WEBSOCKET."
@@ -531,7 +529,7 @@ If the websocket is closed a signal `websocket-closed' is 
sent,
 also with `websocket-error' condition.  The data in the signal is
 also the frame.
 
-The frame may be too large for this buid of emacs, in which case
+The frame may be too large for this buid of Emacs, in which case
 `websocket-frame-too-large' is returned, with the data of the
 size of the frame which was too large to process.  This also has
 the `websocket-error' condition."
@@ -585,7 +583,7 @@ connecting or open."
 ;;;;;;;;;;;;;;;;;;;;;;
 
 (defun* websocket-open (url &key protocols extensions (on-open 'identity)
-                            (on-message (lambda (w f))) (on-close 'identity)
+                            (on-message (lambda (_w _f))) (on-close 'identity)
                             (on-error 'websocket-default-error-handler))
   "Open a websocket connection to URL, returning the `websocket' struct.
 The PROTOCOL argument is optional, and setting it will declare to
@@ -717,7 +715,6 @@ is no more output or the connection closes.  If the 
websocket
 connection is invalid, the connection will be closed."
   (websocket-debug websocket "Received: %s" output)
   (let ((start-point)
-        (end-point 0)
         (text (concat (websocket-inflight-input websocket) output))
         (header-end-pos))
     (setf (websocket-inflight-input websocket) nil)
@@ -763,23 +760,23 @@ of populating the list of server extensions to WEBSOCKET."
       (dolist (protocol (websocket-protocols websocket))
         (websocket-debug websocket "Checking for protocol match: %s"
                          protocol)
-        (let ((protocols))
-          (if (string-match
-               (format "\r\nSec-Websocket-Protocol: %s\r\n"
-                       protocol) output)
-              (add-to-list 'protocols protocol)
-            (signal 'websocket-invalid-header
-                    "Incorrect or missing protocol returned by the server."))
+        (let ((protocols
+               (if (string-match (format "\r\nSec-Websocket-Protocol: %s\r\n"
+                                         protocol)
+                                 output)
+                   (list protocol)
+                 (signal 'websocket-invalid-header
+                         "Incorrect or missing protocol returned by the 
server."))))
           (setf (websocket-negotiated-protocols websocket) protocols))))
     (let* ((extensions (websocket-parse-repeated-field
                         output
                         "Sec-WebSocket-Extensions"))
            (extra-extensions))
       (dolist (ext extensions)
-        (when (not (member
-                    (first (split-string ext "; ?"))
-                    (websocket-extensions websocket)))
-          (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
+        (let ((x (first (split-string ext "; ?"))))
+          (unless (or (member x (websocket-extensions websocket))
+                      (member x extra-extensions))
+            (push x extra-extensions))))
       (when extra-extensions
         (signal 'websocket-invalid-header
                 (format "Non-requested extensions returned by server: %S"
@@ -817,7 +814,8 @@ connection, which should be kept in order to pass to
     (dolist (ws websocket-server-websockets)
       (when (eq (websocket-server-conn ws) conn)
         (if (eq (websocket-ready-state ws) 'closed)
-            (add-to-list 'to-delete ws)
+            (unless (member ws to-delete)
+              (push ws to-delete))
           (websocket-close ws))))
     (dolist (ws to-delete)
       (setq websocket-server-websockets (remove ws 
websocket-server-websockets))))
@@ -830,7 +828,7 @@ connection, which should be kept in order to pass to
              :conn client
              :url client
              :on-open (or (process-get server :on-open) 'identity)
-             :on-message (or (process-get server :on-message) (lambda (ws 
frame)))
+             :on-message (or (process-get server :on-message) (lambda (_ws 
_frame)))
              :on-close (lexical-let ((user-method
                                       (or (process-get server :on-close) 
'identity)))
                          (lambda (ws)
@@ -841,7 +839,8 @@ connection, which should be kept in order to pass to
                            'websocket-default-error-handler)
              :protocols (process-get server :protocol)
              :extensions (mapcar 'car (process-get server :extensions)))))
-    (add-to-list 'websocket-server-websockets ws)
+    (unless (member ws websocket-server-websockets)
+      (push ws websocket-server-websockets))
     (set-process-coding-system client 'unix 'unix)
     (process-put client :websocket ws)
     (set-process-filter client 'websocket-server-filter)

commit bc5c2a2ee2b993a18e8e23ed725829d403508753
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 6 17:46:22 2013 -0400

    Set version to 1.01.

diff --git a/websocket.el b/websocket.el
index b5ada90..ce6249b 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication, Websocket, Server
-;; Version: 1.0
+;; Version: 1.01
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -101,7 +101,7 @@ same for the protocols.
   accept-string
   (inflight-input nil))
 
-(defvar websocket-version "1.0"
+(defvar websocket-version "1.01"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit 6f033f25424768df826b2758e0cfdfa398362299
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 6 15:33:25 2013 -0400

    Stop using deprecated function set-process-filter-multibyte.
    
    Instead, we set the process coding system to binary, which
    accomplishes the same thing.

diff --git a/README.org b/README.org
index a8d42f8..ee20381 100644
--- a/README.org
+++ b/README.org
@@ -17,9 +17,7 @@ Each version that is released should be checked with this 
checklist:
 
 - [ ] All ert test passing
 - [ ] Functional test passing on emacs 23 and 24
-- [ ] websocket.el byte compiling cleanly, except for these exceptions:
-  - =set-process-filter-multibyte= is obsolete, yet I cannot find any
-    other way of ensuring my filter has multibyte disabled.
+- [ ] websocket.el byte compiling cleanly.
 
 * Existing clients:
 
diff --git a/websocket.el b/websocket.el
index 1dc9829..b5ada90 100644
--- a/websocket.el
+++ b/websocket.el
@@ -845,9 +845,7 @@ connection, which should be kept in order to pass to
     (set-process-coding-system client 'unix 'unix)
     (process-put client :websocket ws)
     (set-process-filter client 'websocket-server-filter)
-    ;; set-process-filter-multibyte is obsolete, but make-network-process's
-    ;; :filter-multibyte arg does not seem to do anything.
-    (set-process-filter-multibyte client nil)
+    (set-process-coding-system client 'binary)
     (set-process-sentinel client
      (lambda (process change)
        (let ((websocket (process-get process :websocket)))

commit 4089d1cdb85a55d8e5add426a9c07402ab6ec3a5
Merge: 3e060d9 034e6eb
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 6 15:08:34 2013 -0400

    Merge branch 'master' into compile-fix


commit 034e6eb9154a367f0692f7804f48217a6834620f
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 6 00:49:52 2013 -0400

    Changed websocket-outer-filter test to not use flet with struct.
    
    This caused issues with the eval'd websocket-outer-filter test, for
    unknown reasons.
    
    Instead of using flet, we just do the simpler thing now and setf the
    value as we want it.

diff --git a/websocket-test.el b/websocket-test.el
index f7c5936..c06d7cf 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -371,8 +371,8 @@
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
       (should (equal (list frame2 frame1) processed-frames))
       (should-not (websocket-inflight-input fake-ws)))
-    (flet ((websocket-ready-state (websocket) 'connecting)
-           (websocket-close (websocket)))
+    (flet ((websocket-close (websocket)))
+      (setf (websocket-ready-state fake-ws) 'connecting)
       (should (eq 500 (cdr (should-error
                                 (websocket-outer-filter fake-ws "HTTP/1.1 
500\r\n\r\n")
                                 :type 
'websocket-received-error-http-response)))))))

commit 3e060d98a5cbfb9ea167b9e2e1bb505561d056fe
Author: Andrew Hyatt <address@hidden>
Date:   Fri Jul 5 22:30:11 2013 -0400

    Replace obsolete alias condition-case-no-debug with 
condition-case-unless-debug.

diff --git a/websocket.el b/websocket.el
index fc53ffd..1dc9829 100644
--- a/websocket.el
+++ b/websocket.el
@@ -669,7 +669,7 @@ describing the problem with the frame.
                        (if (eq type 'plain)
                            (make-network-process :name name :buffer buf :host 
host
                                                  :service port :nowait nil)
-                         (condition-case-no-debug nil
+                         (condition-case-unless-debug nil
                              (open-network-stream name buf host port :type 
type :nowait nil)
                            (wrong-number-of-arguments
                             (signal 'websocket-wss-needs-emacs-24 "wss")))))

commit 714dca50644c75884d9d90f10328c7a12e02cdcc
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 19 11:23:57 2013 +0400

    Bump the version

diff --git a/js2-mode.el b/js2-mode.el
index c925ff3..982b794 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130608
+;; Version: 20130619
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 

commit c6ca082c191cecf616fb531958ef390f148bf6d8
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 19 11:08:13 2013 +0400

    js2-next-error: Always echo error text

diff --git a/js2-mode.el b/js2-mode.el
index b1771a9..c925ff3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11139,6 +11139,8 @@ RESET means start over from the beginning."
           (if (zerop (decf count))
               (setq continue nil)))
         (setq errs (cdr errs)))
+      ;; Clear for `js2-echo-error'.
+      (message nil)
       (if err
           (goto-char (second err))
         ;; Wrap around to first error.

commit 9e7c6bd3c54ee17bdd639d27184a2d53681ab630
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 19 01:19:25 2013 +0400

    Fix #106
    
    * Check for an active minibuffer.
    
    * Don't compare with "Quit", we're only called on `point-entered', so
      that message should already be cleared anyway.

diff --git a/js2-mode.el b/js2-mode.el
index 09c5b27..b1771a9 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10562,8 +10562,9 @@ This ensures that the counts and `next-error' are 
correct."
 (defun js2-echo-error (old-point new-point)
   "Called by point-motion hooks."
   (let ((msg (get-text-property new-point 'help-echo)))
-    (when (and (stringp msg) (or (not (current-message))
-                                 (string= (current-message) "Quit")))
+    (when (and (stringp msg)
+               (not (active-minibuffer-window))
+               (not (current-message)))
       (message msg))))
 
 (defalias #'js2-echo-help #'js2-echo-error)

commit 1c53de75e0acd19d61ad45a91b32c183948e5128
Author: Dmitry Gutov <address@hidden>
Date:   Sat Jun 8 13:19:36 2013 +0400

    Introduce js2-init-hook
    
    Fixing #20 (again) in a different way

diff --git a/js2-mode.el b/js2-mode.el
index 812c35b..09c5b27 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130510
+;; Version: 20130608
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 
@@ -854,7 +854,7 @@ First, you can add externs that are valid for all your 
JavaScript files.
 You should probably do this by adding them to `js2-global-externs', which
 is a global list used for all js2-mode files.
 
-Next, you can add a function to `js2-mode-hook' that adds additional
+Next, you can add a function to `js2-init-hook' that adds additional
 externs appropriate for the specific file, perhaps based on its path.
 These should go in `js2-additional-externs', which is buffer-local.
 
@@ -1093,11 +1093,19 @@ Not currently used."
   '((t :foreground "orange"))
   "Face used to highlight undeclared variable identifiers.")
 
+(defcustom js2-init-hook nil
+  "List of functions to be called after `js2-mode' or
+`js2-minor-mode' has initialized all variables, before parsing
+the buffer for the first time."
+  :type 'hook
+  :group 'js2-mode
+  :version "20130608")
+
 (defcustom js2-post-parse-callbacks nil
-  "A list of callback functions invoked after parsing finishes.
+  "List of callback functions invoked after parsing finishes.
 Currently, the main use for this function is to add synthetic
 declarations to `js2-recorded-identifiers', which see."
-  :type 'list
+  :type 'hook
   :group 'js2-mode)
 
 (defcustom js2-highlight-external-variables t
@@ -10112,6 +10120,7 @@ highlighting features of `js2-mode'."
   (add-hook 'change-major-mode-hook #'js2-minor-mode-exit nil t)
   (when js2-include-jslint-globals
     (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
+  (run-hooks 'js2-init-hook)
   (js2-reparse))
 
 (defun js2-minor-mode-exit ()
@@ -10310,6 +10319,8 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
   (when js2-include-jslint-globals
     (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
 
+  (run-hooks 'js2-init-hook)
+
   (js2-reparse))
 
 (defun js2-mode-exit ()

commit ef861dedc420453d91b348107633a3043b371be6
Author: Leo Liu <address@hidden>
Date:   Wed Jun 5 00:47:49 2013 +0800

    New user variable ggtags-completing-read-function
    
    to control completing-read in ggtags-mode.

diff --git a/ggtags.el b/ggtags.el
index 2104556..b545b8f 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -110,6 +110,11 @@ If nil, use Emacs default."
                  (const cscope))
   :group 'ggtags)
 
+(defcustom ggtags-completing-read-function completing-read-function
+  "Ggtags specific `completing-read-function' (which see)."
+  :type 'function
+  :group 'ggtags)
+
 (defvar ggtags-cache nil)               ; (ROOT TABLE DIRTY TIMESTAMP)
 
 (defvar ggtags-current-tag-name nil)
@@ -227,7 +232,8 @@ Return -1 if it does not exist."
 
 (defun ggtags-read-tag (quick)
   (ggtags-ensure-root-directory)
-  (let ((default (thing-at-point 'symbol)))
+  (let ((default (thing-at-point 'symbol))
+        (completing-read-function ggtags-completing-read-function))
     (setq ggtags-current-tag-name
           (if quick (or default (user-error "No tag at point"))
             (completing-read

commit b63de685c2daf93686e902d56f8aca424ec15706
Author: Leo Liu <address@hidden>
Date:   Wed Jun 5 00:00:24 2013 +0800

    Fix #11: Support finding symbol tags (OPTION: -s)

diff --git a/ggtags.el b/ggtags.el
index ca82e8c..2104556 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -227,14 +227,12 @@ Return -1 if it does not exist."
 
 (defun ggtags-read-tag (quick)
   (ggtags-ensure-root-directory)
-  (let* ((tags (ggtags-tag-names))
-         (sym (thing-at-point 'symbol))
-         (default (and (member sym tags) sym)))
+  (let ((default (thing-at-point 'symbol)))
     (setq ggtags-current-tag-name
-          (if quick (or default (error "No valid tag at point"))
+          (if quick (or default (user-error "No tag at point"))
             (completing-read
              (format (if default "Tag (default %s): " "Tag: ") default)
-             tags nil t nil nil default)))))
+             (ggtags-tag-names) nil t nil nil default)))))
 
 (defun ggtags-global-options ()
   (concat "-v --result="
@@ -249,17 +247,20 @@ When called with prefix, ask the name and kind of tag."
   (interactive (list (ggtags-read-tag (not current-prefix-arg))
                      current-prefix-arg))
   (ggtags-check-root-directory)
-  (eval-and-compile (require 'etags))
-  (ggtags-navigation-mode +1)
-  (ring-insert find-tag-marker-ring (point-marker))
   (let ((split-window-preferred-function ggtags-split-window-function)
-        (default-directory (ggtags-root-directory)))
+        (default-directory (ggtags-root-directory))
+        (help-char ??)
+        (help-form "\
+d: definitions          (-d)
+r: references           (-r)
+s: symbols              (-s)
+?: show this help\n"))
     (compilation-start
      (if (or verbose (not buffer-file-name))
-         (format "global %s %s \"%s\""
+         (format "global %s -%s \"%s\""
                  (ggtags-global-options)
-                 (if (y-or-n-p "Find definition (n for reference)? ")
-                     "" "-r")
+                 (char-to-string
+                  (read-char-choice "Tag type? (d/r/s/?) " '(?d ?r ?s)))
                  name)
        (format "global %s --from-here=%d:%s \"%s\""
                (ggtags-global-options)
@@ -267,7 +268,10 @@ When called with prefix, ask the name and kind of tag."
                (shell-quote-argument
                 (expand-file-name (file-truename buffer-file-name)))
                name))
-     'ggtags-global-mode)))
+     'ggtags-global-mode))
+  (eval-and-compile (require 'etags))
+  (ring-insert find-tag-marker-ring (point-marker))
+  (ggtags-navigation-mode +1))
 
 (defun ggtags-find-tag-resume ()
   (interactive)

commit 3334309116496707a52b48ce7f2ce4553a5ffbc4
Author: Leo Liu <address@hidden>
Date:   Tue Jun 4 14:37:23 2013 +0800

    New command ggtags-query-replace

diff --git a/ggtags.el b/ggtags.el
index 3fa79d0..ca82e8c 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6.5
+;; Version: 0.6.6
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -208,10 +208,7 @@ Return -1 if it does not exist."
     (if (ggtags-cache-stale-p root)
         (let* ((default-directory (file-name-as-directory root))
                (tags (with-demoted-errors
-                       (split-string
-                        (with-output-to-string
-                          (call-process "global" nil (list standard-output nil)
-                                        nil "-c" (or prefix "")))))))
+                       (process-lines "global" "-c" (or prefix "")))))
           (and tags (ggtags-cache-set root tags))
           tags)
       (cadr (ggtags-cache-get root)))))
@@ -309,6 +306,33 @@ When called with prefix, ask the name and kind of tag."
       (setq-local compilation-auto-jump-to-first-error nil)
       (remove-hook 'compilation-finish-functions 'ggtags-handle-single-match 
t))))
 
+(defun ggtags-query-replace (from to &optional delimited directory)
+  "Query replace FROM with TO on all files in DIRECTORY."
+  (interactive
+   (append (query-replace-read-args "Query replace (regexp)" t t)
+           (list (read-directory-name "In directory: " nil nil t))))
+  (let ((default-directory (file-name-as-directory directory)))
+    (ggtags-check-root-directory)
+    (dolist (file (process-lines "global" "-P" "-l" "."))
+      (let ((file (expand-file-name file directory)))
+        (when (file-exists-p file)
+          (let* ((message-log-max nil)
+                 (visited (get-file-buffer file))
+                 (buffer (or visited
+                             (with-demoted-errors
+                               (find-file-noselect file)))))
+            (when buffer
+              (set-buffer buffer)
+              (if (save-excursion
+                    (goto-char (point))
+                    (re-search-forward from nil t))
+                  (progn
+                    (switch-to-buffer (current-buffer))
+                    (perform-replace from to t t delimited
+                                     nil multi-query-replace-map))
+                (message "Nothing to do for `%s'" file)
+                (or visited (kill-buffer))))))))))
+
 (defun ggtags-delete-tag-files ()
   "Delete the tag files generated by gtags."
   (interactive)

commit f546cfdd8ede04c5574b3348c7458bdd15497321
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 22:01:18 2013 +0800

    New command ggtags-delete-tag-files

diff --git a/ggtags.el b/ggtags.el
index a37edcb..3fa79d0 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -67,6 +67,10 @@
       (list 'progn (list 'defvar var val docstring)
             (list 'make-variable-buffer-local (list 'quote var))))))
 
+(eval-and-compile
+  (unless (fboundp 'user-error)
+    (defalias 'user-error 'error)))
+
 (defgroup ggtags nil
   "GNU Global source code tagging system."
   :group 'tools)
@@ -305,6 +309,27 @@ When called with prefix, ask the name and kind of tag."
       (setq-local compilation-auto-jump-to-first-error nil)
       (remove-hook 'compilation-finish-functions 'ggtags-handle-single-match 
t))))
 
+(defun ggtags-delete-tag-files ()
+  "Delete the tag files generated by gtags."
+  (interactive)
+  (when (ggtags-root-directory)
+    (let ((files (directory-files (ggtags-root-directory) t
+                                  (regexp-opt '("GPATH" "GRTAGS" "GTAGS" 
"ID"))))
+          (buffer "*GTags File List*"))
+      (or files (user-error "No tag files found"))
+      (with-output-to-temp-buffer buffer
+        (dolist (file files)
+          (princ file)
+          (princ "\n")))
+      (let ((win (get-buffer-window buffer)))
+        (unwind-protect
+            (progn
+              (fit-window-to-buffer win)
+              (when (yes-or-no-p "Remove GNU Global tag files? ")
+                (mapc 'delete-file files)))
+          (when (window-live-p win)
+            (quit-window t win)))))))
+
 (defvar-local ggtags-global-exit-status nil)
 
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)

commit fe5d11f011a2e4b5958d1dd698de7afd10c2f212
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 21:38:37 2013 +0800

    Fix incorrect value of variable ggtags-root-directory
    
    in ggtags-ensure-root-directory. Quote file name in ggtags-list-tags.

diff --git a/ggtags.el b/ggtags.el
index 276acff..a37edcb 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -185,17 +185,19 @@ Return -1 if it does not exist."
 
 (defun ggtags-ensure-root-directory ()
   (or (ggtags-root-directory)
-      (if (yes-or-no-p "File GTAGS not found; run gtags? ")
-          (let ((root (read-directory-name "Directory: " nil nil t)))
-            (and (= (length root) 0) (error "No directory chosen"))
-            (with-temp-buffer
-              (if (zerop (let ((default-directory
-                                 (file-name-as-directory root)))
-                           (call-process "gtags" nil t)))
-                  (message "File GTAGS generated in `%s'"
-                           (ggtags-root-directory))
-                (error "%s" (comment-string-strip (buffer-string) t t)))))
-        (error "Aborted"))))
+      (when (or (yes-or-no-p "File GTAGS not found; run gtags? ")
+                (error "Aborted"))
+        (let ((root (read-directory-name "Directory: " nil nil t)))
+          (and (= (length root) 0) (error "No directory chosen"))
+          (when (with-temp-buffer
+                  (let ((default-directory
+                          (file-name-as-directory root)))
+                    (or (zerop (call-process "gtags" nil t))
+                        (error "%s" (comment-string-strip
+                                     (buffer-string) t t)))))
+            (kill-local-variable 'ggtags-root-directory)
+            (message "File GTAGS generated in `%s'"
+                     (ggtags-root-directory)))))))
 
 (defun ggtags-tag-names-1 (root &optional prefix)
   (when root
@@ -296,8 +298,9 @@ When called with prefix, ask the name and kind of tag."
                                    regexp
                                    (if (file-directory-p file-or-directory)
                                        "-l ."
-                                     (concat "-f " (file-name-nondirectory
-                                                    file-or-directory))))
+                                     (concat "-f " (shell-quote-argument
+                                                    (file-name-nondirectory
+                                                     file-or-directory)))))
                            'ggtags-global-mode)
       (setq-local compilation-auto-jump-to-first-error nil)
       (remove-hook 'compilation-finish-functions 'ggtags-handle-single-match 
t))))

commit 908c6f6e89af8b32b80591bb0095de86a9441156
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 16:10:58 2013 +0800

    Fix #7: New command ggtags-list-tags

diff --git a/ggtags.el b/ggtags.el
index 9dfc10d..276acff 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -245,8 +245,8 @@ If point is at a definition tag, find references, and vice 
versa.
 When called with prefix, ask the name and kind of tag."
   (interactive (list (ggtags-read-tag (not current-prefix-arg))
                      current-prefix-arg))
-  (eval-and-compile (require 'etags))
   (ggtags-check-root-directory)
+  (eval-and-compile (require 'etags))
   (ggtags-navigation-mode +1)
   (ring-insert find-tag-marker-ring (point-marker))
   (let ((split-window-preferred-function ggtags-split-window-function)
@@ -258,10 +258,11 @@ When called with prefix, ask the name and kind of tag."
                  (if (y-or-n-p "Find definition (n for reference)? ")
                      "" "-r")
                  name)
-       (format "global %s --from-here=%d:'%s' \"%s\""
+       (format "global %s --from-here=%d:%s \"%s\""
                (ggtags-global-options)
                (line-number-at-pos)
-               (expand-file-name (file-truename buffer-file-name))
+               (shell-quote-argument
+                (expand-file-name (file-truename buffer-file-name)))
                name))
      'ggtags-global-mode)))
 
@@ -272,6 +273,35 @@ When called with prefix, ask the name and kind of tag."
     (let ((split-window-preferred-function ggtags-split-window-function))
       (compile-goto-error))))
 
+;; NOTE: Coloured output in grep requested: http://goo.gl/Y9IcX
+(defun ggtags-list-tags (regexp file-or-directory)
+  "List all tags matching REGEXP in FILE-OR-DIRECTORY."
+  (interactive (list (read-string "POSIX regexp: ")
+                     (read-file-name "Directory: "
+                                     (if current-prefix-arg
+                                         (ggtags-root-directory)
+                                       default-directory)
+                                     buffer-file-name t)))
+  (let ((split-window-preferred-function ggtags-split-window-function)
+        (default-directory (if (file-directory-p file-or-directory)
+                               (file-name-as-directory file-or-directory)
+                             (file-name-directory file-or-directory))))
+    (ggtags-check-root-directory)
+    (eval-and-compile (require 'etags))
+    (ggtags-navigation-mode +1)
+    (ring-insert find-tag-marker-ring (point-marker))
+    (with-current-buffer
+        (compilation-start (format "global %s -e %s %s"
+                                   (ggtags-global-options)
+                                   regexp
+                                   (if (file-directory-p file-or-directory)
+                                       "-l ."
+                                     (concat "-f " (file-name-nondirectory
+                                                    file-or-directory))))
+                           'ggtags-global-mode)
+      (setq-local compilation-auto-jump-to-first-error nil)
+      (remove-hook 'compilation-finish-functions 'ggtags-handle-single-match 
t))))
+
 (defvar-local ggtags-global-exit-status nil)
 
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)

commit c573b74da1e9056f8a3fbeb826600a8d254c5445
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 15:00:34 2013 +0800

    A few minor fixes
    
    1. Quote path in ggtags-find-tag
    2. Do not close the window if exit abnormally
    3. Tweak ggtags-global-mode-font-lock-keywords

diff --git a/ggtags.el b/ggtags.el
index 47b3ec3..9dfc10d 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -258,7 +258,7 @@ When called with prefix, ask the name and kind of tag."
                  (if (y-or-n-p "Find definition (n for reference)? ")
                      "" "-r")
                  name)
-       (format "global %s --from-here=%d:%s \"%s\""
+       (format "global %s --from-here=%d:'%s' \"%s\""
                (ggtags-global-options)
                (line-number-at-pos)
                (expand-file-name (file-truename buffer-file-name))
@@ -272,7 +272,10 @@ When called with prefix, ask the name and kind of tag."
     (let ((split-window-preferred-function ggtags-split-window-function))
       (compile-goto-error))))
 
+(defvar-local ggtags-global-exit-status nil)
+
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
+  (setq ggtags-global-exit-status exit-status)
   (let ((count (save-excursion
                  (goto-char (point-max))
                  (if (re-search-backward "^\\([0-9]+\\) \\w+ located" nil t)
@@ -338,29 +341,27 @@ When called with prefix, ask the name and kind of tag."
           (ggtags-abbreviate-file (match-beginning sub) (match-end sub)))))))
 
 (defun ggtags-handle-single-match (buf _how)
-  (unless (or (not ggtags-auto-jump-to-first-match)
-              (save-excursion
-                (goto-char (point-min))
-                (ignore-errors
-                  (goto-char (compilation-next-single-property-change
-                              (point) 'compilation-message))
-                  (end-of-line)
-                  (compilation-next-single-property-change
-                   (point) 'compilation-message))))
+  (when (and ggtags-auto-jump-to-first-match
+             ;; If exit abnormally keep the window for inspection.
+             (zerop ggtags-global-exit-status)
+             (save-excursion
+               (goto-char (point-min))
+               (not (ignore-errors
+                      (goto-char (compilation-next-single-property-change
+                                  (point) 'compilation-message))
+                      (end-of-line)
+                      (compilation-next-single-property-change
+                       (point) 'compilation-message)))))
     (ggtags-navigation-mode -1)
     ;; 0.5s delay for `ggtags-auto-jump-to-first-match'
     (sit-for 0)                    ; See: http://debbugs.gnu.org/13829
     (ggtags-navigation-mode-cleanup buf 0.5)))
 
 (defvar ggtags-global-mode-font-lock-keywords
-  '(("^-[*]-.*-[*]-$"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
-    ("^\\w+ not found.*\\|^[0-9]+ \\w+ located.*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
-    ("^Global \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
-     (1 compilation-error-face)
-     (2 compilation-error-face nil t))))
+  '(("^Global \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
+     (1 'compilation-error)
+     (2 'compilation-error nil t))
+    ("^Global found \\([0-9]+\\)" (1 compilation-info-face))))
 
 (define-compilation-mode ggtags-global-mode "Global"
   "A mode for showing outputs from gnu global."

commit e8bb6cc80417af65d9a92cb871cdc4b7283b0eee
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 12:22:29 2013 +0800

    Bump version to 0.6.5

diff --git a/README.rst b/README.rst
index 45d0cfa..e18db58 100644
--- a/README.rst
+++ b/README.rst
@@ -17,6 +17,8 @@ Features
 #. Highlight valid tag at point
 #. Built on top of ``compile.el`` (asynchonrous and other nice
    features)
+#. Support all  output formats  of ``global``:  ``grep``, ``ctags-x``,
+   ``cscope`` etc.
 #. Abbreviated display of file names
 
 Why GNU Global
@@ -24,7 +26,7 @@ Why GNU Global
 
 The opengrok project composed a feature comparison table between a few
 tools. The `page
-<http://hub.opensolaris.org/bin/view/Project+opengrok>`_ is taken
+<http://hub.opensolaris.org/bin/view/Project+opengrok>`_ was taken
 offline after 2013-03-24 but `here <http://i.imgur.com/IQCPQ0j.png>`_
 is a backup.
 
diff --git a/ggtags.el b/ggtags.el
index 491f5ae..47b3ec3 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6.4
+;; Version: 0.6.5
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags

commit 8c9ef10eb295dbbee28f98510c89d7ef1c8d333f
Author: Leo Liu <address@hidden>
Date:   Mon Jun 3 12:02:24 2013 +0800

    Fix false positive error regexp matches
    
    that can fail compilation-auto-jump.

diff --git a/ggtags.el b/ggtags.el
index 231bde9..491f5ae 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -283,6 +283,27 @@ When called with prefix, ask the name and kind of tag."
             (format "found %d %s" count (if (= count 1) "match" "matches")))
           exit-status)))
 
+;;; NOTE: Must not match the 'Global started at Mon Jun 3 10:24:13'
+;;; line or `compilation-auto-jump' will jump there and fail. See
+;;; comments before the 'gnu' entry in
+;;; `compilation-error-regexp-alist-alist'.
+(defvar ggtags-global-error-regexp-alist-alist
+  (append
+   '((path "^\\(?:[^/\n]*/\\)?[^ )\t\n]+$" 0)
+     ;; ACTIVE_ESCAPE  src/dialog.cc   172
+     (ctags "^\\([^ \t\n]+\\)[ \t]+\\(.*?\\)[ \t]+\\([0-9]+\\)$"
+            2 3 nil nil 2 (1 font-lock-function-name-face))
+     ;; ACTIVE_ESCAPE     172 src/dialog.cc    #undef ACTIVE_ESCAPE
+     (ctags-x "^\\([^ \t\n]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(\\(?:[^/\n]*/\\)?[^ 
\t\n]+\\)"
+              3 2 nil nil 3 (1 font-lock-function-name-face))
+     ;; src/dialog.cc:172:#undef ACTIVE_ESCAPE
+     (grep 
"^\\(.+?\\):\\([0-9]+\\):\\(?:[^0-9\n]\\|[0-9][^0-9\n]\\|[0-9][0-9].\\)"
+           1 2 nil nil 1)
+     ;; src/dialog.cc ACTIVE_ESCAPE 172 #undef ACTIVE_ESCAPE
+     (cscope "^\\(.+?\\)[ \t]+\\([^ \t\n]+\\)[ 
\t]+\\([0-9]+\\).*\\(?:[^0-9\n]\\|[^0-9\n][0-9]\\|[^:\n][0-9][0-9]\\)$"
+             1 3 nil nil 1 (2 font-lock-function-name-face)))
+   compilation-error-regexp-alist-alist))
+
 (defun ggtags-abbreviate-file (start end)
   (let ((inhibit-read-only t)
         (amount (if (numberp ggtags-global-abbreviate-filename)
@@ -303,10 +324,10 @@ When called with prefix, ask the name and kind of tag."
 
 (defun ggtags-abbreviate-files (start end)
   (goto-char start)
-  (when (and ggtags-global-abbreviate-filename
-             (ggtags-global-output-format-error-regexp))
-    (let* ((error-re (ggtags-global-output-format-error-regexp))
-           (sub (cadr error-re)))
+  (let* ((error-re (cdr (assq ggtags-global-output-format
+                              ggtags-global-error-regexp-alist-alist)))
+         (sub (cadr error-re)))
+    (when (and ggtags-global-abbreviate-filename error-re)
       (while (re-search-forward (car error-re) end t)
         (when (and (or (not (numberp ggtags-global-abbreviate-filename))
                        (> (length (match-string sub))
@@ -336,38 +357,15 @@ When called with prefix, ask the name and kind of tag."
      (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
     ("^\\w+ not found.*\\|^[0-9]+ \\w+ located.*"
      (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
-    ("^[Gg]lobal \\(?:started\\)?.*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
-    ("^Global found \\([0-9]+\\).*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
-     (1 compilation-info-face nil t))
     ("^Global \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
      (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
      (1 compilation-error-face)
      (2 compilation-error-face nil t))))
 
-(defun ggtags-global-output-format-error-regexp ()
-  "Error regexp according to `ggtags-global-output-format'."
-  (pcase ggtags-global-output-format
-    (`path '("^[^ \t\n]+$" 0))
-    ;; ACTIVE_ESCAPE   src/dialog.cc   172
-    (`ctags '("^\\([^ \t\n]+\\)[ \t]+\\(.*?\\)[ \t]+\\([0-9]+\\)"
-              2 3 nil nil 2 (1 font-lock-function-name-face)))
-    ;; ACTIVE_ESCAPE     172 src/dialog.cc    #undef ACTIVE_ESCAPE
-    (`ctags-x '("^\\([^ \t\n]+\\)[ \t]+\\([0-9]+\\)[ 
\t]+\\(\\(?:[^/\n]*/\\)?[^ \t\n]+\\)"
-                3 2 nil nil 3 (1 font-lock-function-name-face)))
-    ;; src/dialog.cc:172:#undef ACTIVE_ESCAPE
-    (`grep '("^\\(.+?\\):\\([0-9]+\\):" 1 2 nil nil 1))
-    ;; src/dialog.cc ACTIVE_ESCAPE 172 #undef ACTIVE_ESCAPE
-    (`cscope '("^\\(.+?\\)[ \t]+\\([^ \t\n]+\\)[ \t]+\\([0-9]+\\)"
-               1 3 nil nil 1 (2 font-lock-function-name-face)))))
-
 (define-compilation-mode ggtags-global-mode "Global"
   "A mode for showing outputs from gnu global."
-  (when (ggtags-global-output-format-error-regexp)
-    (setq-local compilation-error-regexp-alist
-                (cons (ggtags-global-output-format-error-regexp)
-                      compilation-error-regexp-alist)))
+  (setq-local compilation-error-regexp-alist
+              (list ggtags-global-output-format))
   (setq-local compilation-auto-jump-to-first-error
               ggtags-auto-jump-to-first-match)
   (setq-local compilation-scroll-output 'first-error)

commit 98ffa3dbf0e0d1728ea17dee5c09728163dfc8f5
Author: Leo Liu <address@hidden>
Date:   Thu May 30 20:44:55 2013 +0800

    Handle all 'global' output formats (OPTION: --result)

diff --git a/ggtags.el b/ggtags.el
index 4964db0..231bde9 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -97,6 +97,15 @@ If nil, use Emacs default."
   :type 'function
   :group 'ggtags)
 
+(defcustom ggtags-global-output-format 'grep
+  "The output format for the 'global' command."
+  :type '(choice (const path)
+                 (const ctags)
+                 (const ctags-x)
+                 (const grep)
+                 (const cscope))
+  :group 'ggtags)
+
 (defvar ggtags-cache nil)               ; (ROOT TABLE DIRTY TIMESTAMP)
 
 (defvar ggtags-current-tag-name nil)
@@ -224,10 +233,10 @@ Return -1 if it does not exist."
              (format (if default "Tag (default %s): " "Tag: ") default)
              tags nil t nil nil default)))))
 
-(defvar ggtags-global-options
-  (concat "-v --result=grep"
-          (and ggtags-global-has-path-style " --path-style=shorter"))
-  "Options (as a string) for running `global'.")
+(defun ggtags-global-options ()
+  (concat "-v --result="
+          (symbol-name ggtags-global-output-format)
+          (and ggtags-global-has-path-style " --path-style=shorter")))
 
 ;;;###autoload
 (defun ggtags-find-tag (name &optional verbose)
@@ -245,12 +254,12 @@ When called with prefix, ask the name and kind of tag."
     (compilation-start
      (if (or verbose (not buffer-file-name))
          (format "global %s %s \"%s\""
-                 ggtags-global-options
+                 (ggtags-global-options)
                  (if (y-or-n-p "Find definition (n for reference)? ")
                      "" "-r")
                  name)
        (format "global %s --from-here=%d:%s \"%s\""
-               ggtags-global-options
+               (ggtags-global-options)
                (line-number-at-pos)
                (expand-file-name (file-truename buffer-file-name))
                name))
@@ -266,7 +275,7 @@ When called with prefix, ask the name and kind of tag."
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
   (let ((count (save-excursion
                  (goto-char (point-max))
-                 (if (re-search-backward "^\\([0-9]+\\) objects? located" nil 
t)
+                 (if (re-search-backward "^\\([0-9]+\\) \\w+ located" nil t)
                      (string-to-number (match-string 1))
                    0))))
     (cons (if (> exit-status 0)
@@ -294,15 +303,18 @@ When called with prefix, ask the name and kind of tag."
 
 (defun ggtags-abbreviate-files (start end)
   (goto-char start)
-  (when ggtags-global-abbreviate-filename
-    (while (re-search-forward "^\\([^:\n]+\\):[0-9]+:" end t)
-      (when (and (or (not (numberp ggtags-global-abbreviate-filename))
-                     (> (length (match-string 1))
-                        ggtags-global-abbreviate-filename))
-                 ;; Ignore bogus file lines such as:
-                 ;;     Global found 2 matches at Thu Jan 31 13:45:19
-                 (get-text-property (match-beginning 0) 'compilation-message))
-        (ggtags-abbreviate-file (match-beginning 1) (match-end 1))))))
+  (when (and ggtags-global-abbreviate-filename
+             (ggtags-global-output-format-error-regexp))
+    (let* ((error-re (ggtags-global-output-format-error-regexp))
+           (sub (cadr error-re)))
+      (while (re-search-forward (car error-re) end t)
+        (when (and (or (not (numberp ggtags-global-abbreviate-filename))
+                       (> (length (match-string sub))
+                          ggtags-global-abbreviate-filename))
+                   ;; Ignore bogus file lines such as:
+                   ;;     Global found 2 matches at Thu Jan 31 13:45:19
+                   (get-text-property (match-beginning sub) 
'compilation-message))
+          (ggtags-abbreviate-file (match-beginning sub) (match-end sub)))))))
 
 (defun ggtags-handle-single-match (buf _how)
   (unless (or (not ggtags-auto-jump-to-first-match)
@@ -319,8 +331,43 @@ When called with prefix, ask the name and kind of tag."
     (sit-for 0)                    ; See: http://debbugs.gnu.org/13829
     (ggtags-navigation-mode-cleanup buf 0.5)))
 
+(defvar ggtags-global-mode-font-lock-keywords
+  '(("^-[*]-.*-[*]-$"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
+    ("^\\w+ not found.*\\|^[0-9]+ \\w+ located.*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
+    ("^[Gg]lobal \\(?:started\\)?.*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
+    ("^Global found \\([0-9]+\\).*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
+     (1 compilation-info-face nil t))
+    ("^Global \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
+     (1 compilation-error-face)
+     (2 compilation-error-face nil t))))
+
+(defun ggtags-global-output-format-error-regexp ()
+  "Error regexp according to `ggtags-global-output-format'."
+  (pcase ggtags-global-output-format
+    (`path '("^[^ \t\n]+$" 0))
+    ;; ACTIVE_ESCAPE   src/dialog.cc   172
+    (`ctags '("^\\([^ \t\n]+\\)[ \t]+\\(.*?\\)[ \t]+\\([0-9]+\\)"
+              2 3 nil nil 2 (1 font-lock-function-name-face)))
+    ;; ACTIVE_ESCAPE     172 src/dialog.cc    #undef ACTIVE_ESCAPE
+    (`ctags-x '("^\\([^ \t\n]+\\)[ \t]+\\([0-9]+\\)[ 
\t]+\\(\\(?:[^/\n]*/\\)?[^ \t\n]+\\)"
+                3 2 nil nil 3 (1 font-lock-function-name-face)))
+    ;; src/dialog.cc:172:#undef ACTIVE_ESCAPE
+    (`grep '("^\\(.+?\\):\\([0-9]+\\):" 1 2 nil nil 1))
+    ;; src/dialog.cc ACTIVE_ESCAPE 172 #undef ACTIVE_ESCAPE
+    (`cscope '("^\\(.+?\\)[ \t]+\\([^ \t\n]+\\)[ \t]+\\([0-9]+\\)"
+               1 3 nil nil 1 (2 font-lock-function-name-face)))))
+
 (define-compilation-mode ggtags-global-mode "Global"
   "A mode for showing outputs from gnu global."
+  (when (ggtags-global-output-format-error-regexp)
+    (setq-local compilation-error-regexp-alist
+                (cons (ggtags-global-output-format-error-regexp)
+                      compilation-error-regexp-alist)))
   (setq-local compilation-auto-jump-to-first-error
               ggtags-auto-jump-to-first-match)
   (setq-local compilation-scroll-output 'first-error)

commit a11ba885a58db7092b2f15d181f4c2a28b8ba08c
Author: Leo Liu <address@hidden>
Date:   Thu May 30 20:14:14 2013 +0800

    Make ggtags-highlight-tag-at-point more efficient

diff --git a/ggtags.el b/ggtags.el
index 9676c1d..4964db0 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -52,7 +52,6 @@
 
 (eval-when-compile (require 'cl))
 (require 'compile)
-(require 'etags)                        ; for find-tag-marker-ring
 
 (if (not (fboundp 'comment-string-strip))
     (autoload 'comment-string-strip "newcomment"))
@@ -237,6 +236,7 @@ If point is at a definition tag, find references, and vice 
versa.
 When called with prefix, ask the name and kind of tag."
   (interactive (list (ggtags-read-tag (not current-prefix-arg))
                      current-prefix-arg))
+  (eval-and-compile (require 'etags))
   (ggtags-check-root-directory)
   (ggtags-navigation-mode +1)
   (ring-insert find-tag-marker-ring (point-marker))
@@ -436,10 +436,29 @@ When called with prefix, ask the name and kind of tag."
 
 (defvar ggtags-tag-overlay nil)
 (defvar ggtags-highlight-tag-timer nil)
-(make-variable-buffer-local 'ggtags-tag-overlay)
 
-(defun ggtags-highlight-tag-at-point (buffer)
-  (when (eq buffer (current-buffer))
+(defvar ggtags-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\M-." 'ggtags-find-tag)
+    (define-key map "\M-," 'ggtags-find-tag-resume)
+    (define-key map "\C-c\M-k" 'ggtags-kill-file-buffers)
+    map))
+
+;;;###autoload
+(define-minor-mode ggtags-mode nil
+  :lighter (:eval (if ggtags-navigation-mode "" " GG"))
+  (if ggtags-mode
+      (progn
+        (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
+        (or (executable-find "global")
+            (message "Failed to find GNU Global")))
+    (remove-hook 'after-save-hook 'ggtags-after-save-function t)
+    (and (overlayp ggtags-tag-overlay)
+         (delete-overlay ggtags-tag-overlay))
+    (setq ggtags-tag-overlay nil)))
+
+(defun ggtags-highlight-tag-at-point ()
+  (when ggtags-mode
     (unless (overlayp ggtags-tag-overlay)
       (setq ggtags-tag-overlay (make-overlay (point) (point)))
       (overlay-put ggtags-tag-overlay 'ggtags t))
@@ -457,40 +476,11 @@ When called with prefix, ask the name and kind of tag."
       (cond
        ((not bounds)
         (overlay-put ggtags-tag-overlay 'face nil)
-        (move-overlay ggtags-tag-overlay (point) (point)))
+        (move-overlay ggtags-tag-overlay (point) (point) (current-buffer)))
        ((not (funcall done-p))
-        (move-overlay o (car bounds) (cdr bounds))
+        (move-overlay o (car bounds) (cdr bounds) (current-buffer))
         (overlay-put o 'face (and valid-tag 'ggtags-highlight)))))))
 
-(defun ggtags-post-command-function ()
-  (when (timerp ggtags-highlight-tag-timer)
-    (cancel-timer ggtags-highlight-tag-timer))
-  (setq ggtags-highlight-tag-timer
-        (run-with-idle-timer 0.2 nil 'ggtags-highlight-tag-at-point
-                             (current-buffer))))
-
-(defvar ggtags-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\M-." 'ggtags-find-tag)
-    (define-key map "\M-," 'ggtags-find-tag-resume)
-    (define-key map "\C-c\M-k" 'ggtags-kill-file-buffers)
-    map))
-
-;;;###autoload
-(define-minor-mode ggtags-mode nil
-  :lighter (:eval (if ggtags-navigation-mode "" " GG"))
-  (if ggtags-mode
-      (progn
-        (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
-        (if (executable-find "global")
-            (add-hook 'post-command-hook 'ggtags-post-command-function nil t)
-          (message "Failed to find GNU Global")))
-    (remove-hook 'after-save-hook 'ggtags-after-save-function t)
-    (remove-hook 'post-command-hook 'ggtags-post-command-function t)
-    (and (overlayp ggtags-tag-overlay)
-         (delete-overlay ggtags-tag-overlay))
-    (setq ggtags-tag-overlay nil)))
-
 ;;; imenu
 
 (defun ggtags-goto-imenu-index (name line &rest _args)
@@ -542,6 +532,12 @@ When called with prefix, ask the name and kind of tag."
 
 ;;; Finish up
 
+(when ggtags-highlight-tag-timer
+  (cancel-timer ggtags-highlight-tag-timer))
+
+(setq ggtags-highlight-tag-timer
+      (run-with-idle-timer 0.2 t 'ggtags-highlight-tag-at-point))
+
 ;; Higher priority for `ggtags-navigation-mode' to avoid being
 ;; hijacked by modes such as `view-mode'.
 (defvar ggtags-mode-map-alist

commit 0b786f9e8b050c397ee0740ebe955d6daaa9e010
Author: Leo Liu <address@hidden>
Date:   Wed May 29 19:32:08 2013 +0800

    Fix #9: Resolve symlinks before passing to 'global'

diff --git a/ggtags.el b/ggtags.el
index 4262e18..9676c1d 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6.3
+;; Version: 0.6.4
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -252,7 +252,7 @@ When called with prefix, ask the name and kind of tag."
        (format "global %s --from-here=%d:%s \"%s\""
                ggtags-global-options
                (line-number-at-pos)
-               (expand-file-name buffer-file-name)
+               (expand-file-name (file-truename buffer-file-name))
                name))
      'ggtags-global-mode)))
 

commit 2cbe8d9cbd9151ca94b970eb567bba073fa088ff
Author: Leo Liu <address@hidden>
Date:   Wed May 29 08:43:02 2013 +0800

    Fix #8: Avoid closing ECB compilation window

diff --git a/ggtags.el b/ggtags.el
index a41079f..4262e18 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -367,7 +367,7 @@ When called with prefix, ask the name and kind of tag."
              (kill-compilation))
            (when (and (derived-mode-p 'ggtags-global-mode)
                       (get-buffer-window))
-             (delete-window (get-buffer-window)))
+             (quit-window nil (get-buffer-window)))
            (and time (run-with-idle-timer time nil 'kill-buffer buf))))))
 
 (defun ggtags-navigation-mode-done ()

commit 764d2aa4ba50081adf69408e62d4863905b68b7f
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 07:10:43 2013 +0400

    Release 0.6.10

diff --git a/NEWS.md b/NEWS.md
index b6459c7..64860ba 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,6 @@
 # History of user-visible changes
 
-## Next
+## 2013-05-26 (0.6.10)
 
 * Plays nicer with `org-indent-mode`.
 * Works in horizontally scrolled windows.
diff --git a/company.el b/company.el
index 9a916c7..39a3a17 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.9
+;; Version: 0.6.10
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.io/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit 900a78dbaac691a6a852eb6e19bff16370de8add
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 06:59:04 2013 +0400

    company-doc-buffer: Use the arg; rename the buffer

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 73bb33d..0ba26e6 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -43,9 +43,7 @@
   "Return buffer with docstring of CANDIDATE if it is available."
   (let ((doc (company-with-candidate-inserted candidate (rope-get-doc))))
     (when doc
-      (with-current-buffer (company-doc-buffer)
-        (insert doc)
-        (current-buffer)))))
+      (company-doc-buffer doc))))
 
 (defun company-ropemacs-location (candidate)
   "Return location of CANDIDATE in cons form (FILE . LINE) if it is available."
diff --git a/company-semantic.el b/company-semantic.el
index 92cd178..796cc9e 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -74,11 +74,10 @@
 (defun company-semantic-doc-buffer (tag)
   (let ((doc (semantic-documentation-for-tag tag)))
     (when doc
-      (with-current-buffer (company-doc-buffer)
-        (insert (funcall semantic-idle-summary-function tag nil t)
-                "\n"
-                doc)
-        (current-buffer)))))
+      (company-doc-buffer
+       (concat (funcall semantic-idle-summary-function tag nil t)
+               "\n"
+               doc)))))
 
 (defsubst company-semantic-completions (prefix)
   (ignore-errors
diff --git a/company.el b/company.el
index ec6834b..9a916c7 100644
--- a/company.el
+++ b/company.el
@@ -1458,9 +1458,12 @@ To show the number next to the candidates in some 
back-ends, enable
             (cons selected (company-call-backend 'meta selected))))
     (cdr company-last-metadata)))
 
-(defun company-doc-buffer (&optional _string)
-  (with-current-buffer (get-buffer-create "*Company meta-data*")
+(defun company-doc-buffer (&optional string)
+  (with-current-buffer (get-buffer-create "*company-documentation*")
     (erase-buffer)
+    (when string
+      (save-excursion
+        (insert string)))
     (current-buffer)))
 
 (defvar company--electric-commands

commit 1d28760268f22306673b718bb3101c4121699685
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 06:46:01 2013 +0400

    company-backends: Tweak the documentation

diff --git a/company.el b/company.el
index d37780b..ec6834b 100644
--- a/company.el
+++ b/company.el
@@ -273,8 +273,8 @@ return value should be a list of candidates that start with 
the prefix.
 
 Optional commands:
 
-`sorted': The back-end may return t here to indicate that the candidates
-are sorted and will not need to be sorted again.
+`sorted': Return t here to indicate that the candidates are sorted and will
+not need to be sorted again.
 
 `duplicates': If non-nil, company will take care of removing duplicates
 from the list.
@@ -283,25 +283,24 @@ from the list.
 progresses, unless the back-end returns t for this command.  The second
 argument is the latest prefix.
 
-`meta': The second argument is a completion candidate.  The back-end should
-return a (short) documentation string for it.
+`meta': The second argument is a completion candidate.  Return a (short)
+documentation string for it.
 
-`doc-buffer': The second argument is a completion candidate.
-The back-end should create a buffer (preferably with `company-doc-buffer'),
-fill it with documentation and return it.
+`doc-buffer': The second argument is a completion candidate.  Return a
+buffer with documentation for it.  Preferably use `company-doc-buffer',
 
-`location': The second argument is a completion candidate.  The back-end
-can return the cons of buffer and buffer location, or of file and line
-number where the completion candidate was defined.
+`location': The second argument is a completion candidate.  Return the cons
+of buffer and buffer location, or of file and line number where the
+completion candidate was defined.
 
-`require-match': If this value is t, the user is not allowed to enter
+`require-match': If this returns t, the user is not allowed to enter
 anything not offered as a candidate.  Use with care!  The default value nil
 gives the user that choice with `company-require-match'.  Return value
-'never overrides that option the other way around.
+`never' overrides that option the other way around.
 
-`init': Called once for each buffer, the back-end can check for external
+`init': Called once for each buffer. The back-end can check for external
 programs and files and load any required libraries.  Raising an error here
-will show up in message log once, and the backend will not be used for
+will show up in message log once, and the back-end will not be used for
 completion.
 
 `post-completion': Called after a completion candidate has been inserted

commit 100912d9c7a77d6349023a6cf91da05dc9f6e7ea
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 06:36:36 2013 +0400

    Set emacs-lisp-docstring-fill-column to 75,
    
    wrap some overly long lines.

diff --git a/.dir-locals.el b/.dir-locals.el
index 0f821cf..79d9a12 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,4 +1,4 @@
 ((nil . ((indent-tabs-mode . nil)
          (fill-column . 80)
          (sentence-end-double-space . t)
-         (emacs-lisp-docstring-fill-column . t))))
+         (emacs-lisp-docstring-fill-column . 75))))
diff --git a/company-clang.el b/company-clang.el
index a26c691..52bb6e6 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -39,17 +39,18 @@
   :type 'file)
 
 (defcustom company-clang-begin-after-member-access t
-  "When non-nil, automatic completion will start whenever the current symbol is
-preceded by \".\", \"->\" or \"::\", ignoring `company-minimum-prefix-length'.
+  "When non-nil, automatic completion will start whenever the current
+symbol is preceded by \".\", \"->\" or \"::\", ignoring
+`company-minimum-prefix-length'.
 
-If `company-begin-commands' is a list, it should include `c-electric-lt-gt' and
-`c-electric-colon', for automatic completion right after \">\" and \":\".")
+If `company-begin-commands' is a list, it should include `c-electric-lt-gt'
+and `c-electric-colon', for automatic completion right after \">\" and
+\":\".")
 
 (defcustom company-clang-arguments nil
   "Additional arguments to pass to clang when completing.
-Prefix files (-include ...) can be selected with
-`company-clang-set-prefix' or automatically through a custom
-`company-clang-prefix-guesser'."
+Prefix files (-include ...) can be selected with `company-clang-set-prefix'
+or automatically through a custom `company-clang-prefix-guesser'."
   :type '(repeat (string :tag "Argument" nil)))
 
 (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
@@ -265,9 +266,9 @@ Additional command line arguments can be specified in
 with `company-clang-set-prefix' or automatically through a custom
 `company-clang-prefix-guesser'.
 
-With Clang versions before 2.9, we have to save the buffer before performing
-completion.  With Clang 2.9 and later, buffer contents are passed via standard
-input."
+With Clang versions before 2.9, we have to save the buffer before
+performing completion.  With Clang 2.9 and later, buffer contents are
+passed via standard input."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-clang))
diff --git a/company.el b/company.el
index 4d1a59e..d37780b 100644
--- a/company.el
+++ b/company.el
@@ -260,12 +260,13 @@ Each back-end is a function that takes a variable number 
of arguments.
 The first argument is the command requested from the back-end.  It is one
 of the following:
 
-`prefix': The back-end should return the text to be completed.  It must be text
-immediately before point.  Returning nil passes control to the next back-end.
-The function should return `stop' if it should complete but cannot \(e.g. if it
-is in the middle of a string\).  Instead of a string, the back-end may return a
-cons where car is the prefix and cdr is used in `company-minimum-prefix-length'
-test. It's either number or t, in which case the test automatically succeeds.
+`prefix': The back-end should return the text to be completed.  It must be
+text immediately before point.  Returning nil passes control to the next
+back-end.  The function should return `stop' if it should complete but
+cannot \(e.g. if it is in the middle of a string\).  Instead of a string,
+the back-end may return a cons where car is the prefix and cdr is used in
+`company-minimum-prefix-length' test. It's either number or t, in which
+case the test automatically succeeds.
 
 `candidates': The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.
@@ -289,22 +290,23 @@ return a (short) documentation string for it.
 The back-end should create a buffer (preferably with `company-doc-buffer'),
 fill it with documentation and return it.
 
-`location': The second argument is a completion candidate.  The back-end can
-return the cons of buffer and buffer location, or of file and line
+`location': The second argument is a completion candidate.  The back-end
+can return the cons of buffer and buffer location, or of file and line
 number where the completion candidate was defined.
 
-`require-match': If this value is t, the user is not allowed to enter anything
-not offered as a candidate.  Use with care!  The default value nil gives the
-user that choice with `company-require-match'.  Return value 'never overrides
-that option the other way around.
+`require-match': If this value is t, the user is not allowed to enter
+anything not offered as a candidate.  Use with care!  The default value nil
+gives the user that choice with `company-require-match'.  Return value
+'never overrides that option the other way around.
 
 `init': Called once for each buffer, the back-end can check for external
-programs and files and load any required libraries.  Raising an error here will
-show up in message log once, and the backend will not be used for completion.
+programs and files and load any required libraries.  Raising an error here
+will show up in message log once, and the backend will not be used for
+completion.
 
-`post-completion': Called after a completion candidate has been inserted into
-the buffer.  The second argument is the candidate.  Can be used to modify it,
-e.g. to expand a snippet.
+`post-completion': Called after a completion candidate has been inserted
+into the buffer.  The second argument is the candidate.  Can be used to
+modify it, e.g. to expand a snippet.
 
 The back-end should return nil for all commands it does not support or
 does not know about.  It should also be callable interactively and use
@@ -340,8 +342,8 @@ aborted manually."
   "Hook run when company successfully completes.
 The hook is called with the selected candidate as an argument.
 
-If you indend to use it to post-process candidates from a specific back-end,
-consider using the `post-completion' command instead."
+If you indend to use it to post-process candidates from a specific
+back-end, consider using the `post-completion' command instead."
   :type 'hook)
 
 (defcustom company-minimum-prefix-length 3
@@ -362,8 +364,8 @@ This can be overridden by the back-end, if it returns t or 
`never' to
 
 (defcustom company-auto-complete nil
   "Determines when to auto-complete.
-If this is enabled, all characters from `company-auto-complete-chars' complete
-the selected completion.  This can also be a function."
+If this is enabled, all characters from `company-auto-complete-chars'
+complete the selected completion.  This can also be a function."
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
                  (const :tag "On, if user interaction took place"
@@ -372,8 +374,8 @@ the selected completion.  This can also be a function."
 
 (defcustom company-auto-complete-chars '(?\  ?\) ?.)
   "Determines which characters trigger an automatic completion.
-See `company-auto-complete'.  If this is a string, each string character causes
-completion.  If it is a list of syntax description characters (see
+See `company-auto-complete'.  If this is a string, each string character
+causes completion.  If it is a list of syntax description characters (see
 `modify-syntax-entry'), all characters with that syntax auto-complete.
 
 This can also be a function, which is called with the new input and should
@@ -410,8 +412,8 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
   "A list of commands following which company will start completing.
 If this is t, it will complete after any command.  See `company-idle-delay'.
 
-Alternatively any command with a non-nil 'company-begin property is treated as
-if it was on this list."
+Alternatively any command with a non-nil `company-begin' property is treated
+as if it was on this list."
   :type '(choice (const :tag "Any command" t)
                  (const :tag "Self insert command" '(self-insert-command))
                  (repeat :tag "Commands" function)))
@@ -501,9 +503,9 @@ Completions can be searched with 
`company-search-candidates' or
 `company-filter-candidates'.  These can be used while completion is
 inactive, as well.
 
-The completion data is retrieved using `company-backends' and displayed using
-`company-frontends'.  If you want to start a specific back-end, call it
-interactively or use `company-begin-backend'.
+The completion data is retrieved using `company-backends' and displayed
+using `company-frontends'.  If you want to start a specific back-end, call
+it interactively or use `company-begin-backend'.
 
 regular keymap (`company-mode-map'):
 
@@ -1260,8 +1262,8 @@ Don't start this directly, use 
`company-search-candidates' or
 
 Regular characters are appended to the search string.
 
-The command `company-search-kill-others' (\\[company-search-kill-others]) uses
- the search string to limit the completion candidates."
+The command `company-search-kill-others' (\\[company-search-kill-others])
+uses the search string to limit the completion candidates."
   (interactive)
   (company-search-mode 1)
   (company-enable-overriding-keymap company-search-map))
@@ -1393,8 +1395,9 @@ and invoke the normal binding."
 
 (defun company-complete ()
   "Complete the common part of all candidates or the current selection.
-The first time this is called, the common part is completed, the second time, 
or
-when the selection has been changed, the selected candidate is completed."
+The first time this is called, the common part is completed, the second
+time, or when the selection has been changed, the selected candidate is
+completed."
   (interactive)
   (when (company-manual-begin)
     (if (or company-selection-changed
@@ -1487,7 +1490,7 @@ To show the number next to the candidates in some 
back-ends, enable
     (setq unread-command-events (list last-input-event))))
 
 (defun company-show-doc-buffer ()
-  "Temporarily show a buffer with the complete documentation for the 
selection."
+  "Temporarily show the documentation buffer for the selection."
   (interactive)
   (company--electric-do
     (let* ((selected (nth company-selection company-candidates))
@@ -1553,14 +1556,14 @@ To show the number next to the candidates in some 
back-ends, enable
 (defun company-begin-with (candidates
                            &optional prefix-length require-match callback)
   "Start a completion at point.
-CANDIDATES is the list of candidates to use and PREFIX-LENGTH is the length of
-the prefix that already is in the buffer before point.  It defaults to 0.
+CANDIDATES is the list of candidates to use and PREFIX-LENGTH is the length
+of the prefix that already is in the buffer before point.
+It defaults to 0.
 
-CALLBACK is a function called with the selected result if the user successfully
-completes the input.
+CALLBACK is a function called with the selected result if the user
+successfully completes the input.
 
-Example:
-\(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
+Example: \(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
   ;; FIXME: When Emacs 23 is no longer a concern, replace
   ;; `company-begin-with-marker' with a lexical variable; use a lexical 
closure.
   (setq company-begin-with-marker (copy-marker (point) t))

commit a671e2ba473eee74cf385026be0f919a7de0cc86
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 06:17:30 2013 +0400

    company-modify-line: Barf the concat

diff --git a/company.el b/company.el
index 1a98036..4d1a59e 100644
--- a/company.el
+++ b/company.el
@@ -1674,10 +1674,10 @@ Example:
   (let ((prefix (get-text-property 0 'line-prefix old)))
     (when prefix ; Keep the original value unmodified, for no special reason.
       (setq old (concat prefix old))
-      (remove-text-properties 0 (length old) '(line-prefix) old))
-    (concat (company-safe-substring old 0 offset)
-            new
-            (company-safe-substring old (+ offset (length new))))))
+      (remove-text-properties 0 (length old) '(line-prefix) old)))
+  (concat (company-safe-substring old 0 offset)
+          new
+          (company-safe-substring old (+ offset (length new)))))
 
 (defsubst company--length-limit (lst limit)
   (if (nthcdr limit lst)

commit d2587c44cefd96b52a27bbc296cb8156eb2ad773
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 26 06:03:06 2013 +0400

    company-modify-line: Handle an empty first line with line-prefix
    
    * Fixes #24 follow-up.
    * Cleaner code, less display magic.

diff --git a/company-tests.el b/company-tests.el
index 604e8c2..9f837cb 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -212,14 +212,18 @@
 
 (ert-deftest company-modify-line-with-line-prefix ()
   (let ((str (propertize "foobar" 'line-prefix "-*-")))
-    (should (string= (company-modify-line str "zz" 4)
-                     "fzzbar"))
-    (should (string= (company-modify-line str "zzxx" 0)
-                     "zzxxoobar"))
-    (should (string= (company-modify-line str "zzxx" 0)
-                     "zzxxoobar"))
-    (should (string= (company-modify-line str "zz" 10)
-                     "foobar zz"))))
+    (should (equal-including-properties
+             (company-modify-line str "zz" 4)
+             "-*-fzzbar"))
+    (should (equal-including-properties
+             (company-modify-line str "zzxx" 1)
+             "-zzxxobar"))
+    (should (equal-including-properties
+             (company-modify-line str "xx" 0)
+             "xx-foobar"))
+    (should (equal-including-properties
+             (company-modify-line str "zz" 10)
+             "-*-foobar zz"))))
 
 ;;; Template
 
diff --git a/company.el b/company.el
index f4b91c3..1a98036 100644
--- a/company.el
+++ b/company.el
@@ -1671,16 +1671,13 @@ Example:
     (nreverse lines)))
 
 (defun company-modify-line (old new offset)
-  (let ((prefix (get-text-property 0 'line-prefix old))
-        before)
-    (when prefix
-      (if (<= offset (length prefix))
-        (setq before (substring prefix 0 offset)))
-      (decf offset (length prefix)))
-    (concat (or before (company-safe-substring old 0 offset))
+  (let ((prefix (get-text-property 0 'line-prefix old)))
+    (when prefix ; Keep the original value unmodified, for no special reason.
+      (setq old (concat prefix old))
+      (remove-text-properties 0 (length old) '(line-prefix) old))
+    (concat (company-safe-substring old 0 offset)
             new
-            (company-safe-substring old
-                                    (max (+ offset (length new)) 0)))))
+            (company-safe-substring old (+ offset (length new))))))
 
 (defsubst company--length-limit (lst limit)
   (if (nthcdr limit lst)
@@ -1850,6 +1847,8 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (overlay-put company-pseudo-tooltip-overlay 'invisible t)
     ;; Beat outline's folding overlays, at least.
     (overlay-put company-pseudo-tooltip-overlay 'priority 1)
+    ;; No (extra) prefix for the first line.
+    (overlay-put company-pseudo-tooltip-overlay 'line-prefix "")
     (overlay-put company-pseudo-tooltip-overlay 'before-string
                  (overlay-get company-pseudo-tooltip-overlay 'company-before))
     (overlay-put company-pseudo-tooltip-overlay 'window (selected-window))))

commit b869cde68a1cae6f7d81bcc2bf0af88dc1c80f79
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 22:53:55 2013 +0400

    company-modify-line, company--column: Simplify

diff --git a/company.el b/company.el
index 2a17bdd..f4b91c3 100644
--- a/company.el
+++ b/company.el
@@ -574,16 +574,14 @@ keymap during active completions (`company-active-map'):
 (defun company--column (&optional pos)
   (save-excursion
     (when pos (goto-char pos))
-    (let ((pt (point))
-          (modifier 0))
+    (let ((pt (point)))
       (save-restriction
-        (save-excursion
-          (vertical-motion 0)
-          (narrow-to-region (point) pt)
-          (let ((prefix (get-text-property (point) 'line-prefix)))
-            (when prefix (setq modifier (length prefix)))))
-        (+ (current-column)
-           modifier)))))
+        (+ (save-excursion
+             (vertical-motion 0)
+             (narrow-to-region (point) pt)
+             (let ((prefix (get-text-property (point) 'line-prefix)))
+               (if prefix (length prefix) 0)))
+           (current-column))))))
 
 (defun company--row (&optional pos)
   (save-excursion
@@ -1682,8 +1680,7 @@ Example:
     (concat (or before (company-safe-substring old 0 offset))
             new
             (company-safe-substring old
-                                    (let ((to (+ offset (length new))))
-                                      (if (> to 0) to 0))))))
+                                    (max (+ offset (length new)) 0)))))
 
 (defsubst company--length-limit (lst limit)
   (if (nthcdr limit lst)

commit 7499a00484fae37d8b6cc75861aa08f26418788a
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 22:06:13 2013 +0400

    company-ropemacs: Move dependencies list into the docstring

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 17a660a..73bb33d 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -22,8 +22,6 @@
 
 ;;; Commentary:
 ;;
-;; Requires pymacs Emacs package (you can get it from Marmalade),
-;; and on Python side: pymacs, rope, ropemacs and ropemode.
 
 ;;; Code:
 
@@ -57,7 +55,10 @@
       (cons (elt location 0) (elt location 1)))))
 
 (defun company-ropemacs (command &optional arg &rest ignored)
-  "`company-mode' completion back-end for ropemacs."
+  "`company-mode' completion back-end for ropemacs.
+
+Depends on third-party code: Pymacs (both Python and Emacs packages),
+rope, ropemacs and ropemode."
   (interactive (list 'interactive))
   (case command
     (init (when (and (derived-mode-p 'python-mode)

commit e374ba2ca46113722559ba0f87204530ad8c9d47
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 21:53:36 2013 +0400

    company-echo-show-when-not-busy: Remove, was unused

diff --git a/company.el b/company.el
index 9950508..2a17bdd 100644
--- a/company.el
+++ b/company.el
@@ -1966,11 +1966,6 @@ Returns a negative number if the tooltip should be 
displayed above point."
   (setq company-echo-timer (run-with-timer 0 nil 'company-echo-show getter)))
 
 (defsubst company-echo-show-when-idle (&optional getter)
-  (when (sit-for .01)
-    (company-echo-show getter)))
-
-(defsubst company-echo-show-when-not-busy (&optional getter)
-  "Run `company-echo-show' with arg GETTER once Emacs isn't busy."
   (when (sit-for company-echo-delay)
     (company-echo-show getter)))
 

commit 9150eca78f27925ba72389e830c32f36b3368784
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 20:12:26 2013 +0400

    Turn a bunch of defsubsts into defuns

diff --git a/company.el b/company.el
index 7085680..9950508 100644
--- a/company.el
+++ b/company.el
@@ -725,7 +725,7 @@ can retrieve meta-data for them."
   (or company--explicit-action
       company-selection-changed))
 
-(defsubst company-reformat (candidate)
+(defun company-reformat (candidate)
   ;; company-ispell needs this, because the results are always lower-case
   ;; It's mory efficient to fix it only when they are displayed.
   (concat company-prefix (substring candidate (length company-prefix))))
@@ -743,14 +743,14 @@ can retrieve meta-data for them."
            (and (symbolp this-command) (get this-command 'company-begin)))
        (not (and transient-mark-mode mark-active))))
 
-(defsubst company-call-frontends (command)
+(defun company-call-frontends (command)
   (dolist (frontend company-frontends)
     (condition-case err
         (funcall frontend command)
       (error (error "Company: Front-end %s error \"%s\" on command %s"
                     frontend (error-message-string err) command)))))
 
-(defsubst company-set-selection (selection &optional force-update)
+(defun company-set-selection (selection &optional force-update)
   (setq selection (max 0 (min (1- company-candidates-length) selection)))
   (when (or force-update (not (equal selection company-selection)))
     (setq company-selection selection
@@ -1425,7 +1425,7 @@ To show the number next to the candidates in some 
back-ends, enable
       (push (make-string (- company-space-strings-limit 1 i) ?\  ) lst))
     (apply 'vector lst)))
 
-(defsubst company-space-string (len)
+(defun company-space-string (len)
   (if (< len company-space-strings-limit)
       (aref company-space-strings len)
     (make-string len ?\ )))
@@ -1672,7 +1672,7 @@ Example:
       (push (buffer-substring beg end) lines))
     (nreverse lines)))
 
-(defsubst company-modify-line (old new offset)
+(defun company-modify-line (old new offset)
   (let ((prefix (get-text-property 0 'line-prefix old))
         before)
     (when prefix
@@ -1783,7 +1783,7 @@ Example:
   (let ((edges (window-inside-edges)))
     (- (nth 3 edges) (nth 1 edges))))
 
-(defsubst company--pseudo-tooltip-height ()
+(defun company--pseudo-tooltip-height ()
   "Calculate the appropriate tooltip height.
 Returns a negative number if the tooltip should be displayed above point."
   (let* ((lines (company--row))
@@ -1960,7 +1960,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
         (message "%s" company-echo-last-msg)
       (message ""))))
 
-(defsubst company-echo-show-soon (&optional getter)
+(defun company-echo-show-soon (&optional getter)
   (when company-echo-timer
     (cancel-timer company-echo-timer))
   (setq company-echo-timer (run-with-timer 0 nil 'company-echo-show getter)))

commit d02dd88006c5584e434e7f7ca9f4954ab5f8b7ee
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 07:25:39 2013 +0400

    Fix #24, part second
    
    Regression from a696ca3a.

diff --git a/company.el b/company.el
index 84b9bd3..7085680 100644
--- a/company.el
+++ b/company.el
@@ -1656,13 +1656,20 @@ Example:
 (defun company-buffer-lines (beg end)
   (goto-char beg)
   (let (lines)
-    (while (< (point) end)
-      (let ((bol (point)))
+    (while (and (= 1 (vertical-motion 1))
+                (<= (point) end))
+      (let ((bound (min end (1- (point)))))
         ;; A visual line can contain several physical lines (e.g. with 
outline's
         ;; folding overlay).  Take only the first one.
-        (re-search-forward "$")
-        (push (buffer-substring bol (min end (point))) lines))
-      (vertical-motion 1))
+        (push (buffer-substring beg
+                                (save-excursion
+                                  (goto-char beg)
+                                  (re-search-forward "$" bound 'move)
+                                  (point)))
+              lines))
+      (setq beg (point)))
+    (unless (eq beg end)
+      (push (buffer-substring beg end) lines))
     (nreverse lines)))
 
 (defsubst company-modify-line (old new offset)

commit 55ee07cf95e177ce1a5e3d23a53d354749314846
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 05:15:58 2013 +0400

    Respect line-prefix at bol (#24)

diff --git a/NEWS.md b/NEWS.md
index e5ad713..b6459c7 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Plays nicer with `org-indent-mode`.
 * Works in horizontally scrolled windows.
 
 ## 2013-05-10 (0.6.9)
diff --git a/company-tests.el b/company-tests.el
index 7833725..604e8c2 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -204,6 +204,23 @@
     (compose-region 1 (1+ (length "lambda")) "\\")
     (should (= (company--column) 4))))
 
+(ert-deftest company-column-with-line-prefix ()
+  (with-temp-buffer
+    (insert "foo")
+    (put-text-property (point-min) (point) 'line-prefix "  ")
+    (should (= (company--column) 5))))
+
+(ert-deftest company-modify-line-with-line-prefix ()
+  (let ((str (propertize "foobar" 'line-prefix "-*-")))
+    (should (string= (company-modify-line str "zz" 4)
+                     "fzzbar"))
+    (should (string= (company-modify-line str "zzxx" 0)
+                     "zzxxoobar"))
+    (should (string= (company-modify-line str "zzxx" 0)
+                     "zzxxoobar"))
+    (should (string= (company-modify-line str "zz" 10)
+                     "foobar zz"))))
+
 ;;; Template
 
 (ert-deftest company-template-removed-after-the-last-jump ()
diff --git a/company.el b/company.el
index 47f0f61..84b9bd3 100644
--- a/company.el
+++ b/company.el
@@ -574,11 +574,16 @@ keymap during active completions (`company-active-map'):
 (defun company--column (&optional pos)
   (save-excursion
     (when pos (goto-char pos))
-    (save-restriction
-      (narrow-to-region (save-excursion
-                          (vertical-motion 0) (point))
-                        (point))
-      (current-column))))
+    (let ((pt (point))
+          (modifier 0))
+      (save-restriction
+        (save-excursion
+          (vertical-motion 0)
+          (narrow-to-region (point) pt)
+          (let ((prefix (get-text-property (point) 'line-prefix)))
+            (when prefix (setq modifier (length prefix)))))
+        (+ (current-column)
+           modifier)))))
 
 (defun company--row (&optional pos)
   (save-excursion
@@ -1425,7 +1430,7 @@ To show the number next to the candidates in some 
back-ends, enable
       (aref company-space-strings len)
     (make-string len ?\ )))
 
-(defsubst company-safe-substring (str from &optional to)
+(defun company-safe-substring (str from &optional to)
   (if (> from (string-width str))
       ""
     (with-temp-buffer
@@ -1661,9 +1666,17 @@ Example:
     (nreverse lines)))
 
 (defsubst company-modify-line (old new offset)
-  (concat (company-safe-substring old 0 offset)
-          new
-          (company-safe-substring old (+ offset (length new)))))
+  (let ((prefix (get-text-property 0 'line-prefix old))
+        before)
+    (when prefix
+      (if (<= offset (length prefix))
+        (setq before (substring prefix 0 offset)))
+      (decf offset (length prefix)))
+    (concat (or before (company-safe-substring old 0 offset))
+            new
+            (company-safe-substring old
+                                    (let ((to (+ offset (length new))))
+                                      (if (> to 0) to 0))))))
 
 (defsubst company--length-limit (lst limit)
   (if (nthcdr limit lst)

commit 6f2d10ada20e0854033019c38bfdf74a57a34cd2
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 21 03:20:53 2013 +0400

    company--column: Account for character composition

diff --git a/company-tests.el b/company-tests.el
index a8bdaa9..7833725 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -180,6 +180,7 @@
         (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
 
 (ert-deftest company-pseudo-tooltip-overlay-show ()
+  :tags '(interactive)
   (with-temp-buffer
     (save-window-excursion
     (set-window-buffer nil (current-buffer))
@@ -197,6 +198,12 @@
         (should (string= (overlay-get ov 'company-before)
                          " 123\nc45 c\nddd\n")))))))
 
+(ert-deftest company-column-with-composition ()
+  (with-temp-buffer
+    (insert "lambda ()")
+    (compose-region 1 (1+ (length "lambda")) "\\")
+    (should (= (company--column) 4))))
+
 ;;; Template
 
 (ert-deftest company-template-removed-after-the-last-jump ()
diff --git a/company.el b/company.el
index 55e5d1c..47f0f61 100644
--- a/company.el
+++ b/company.el
@@ -574,7 +574,11 @@ keymap during active completions (`company-active-map'):
 (defun company--column (&optional pos)
   (save-excursion
     (when pos (goto-char pos))
-    (- (point) (progn (vertical-motion 0) (point)))))
+    (save-restriction
+      (narrow-to-region (save-excursion
+                          (vertical-motion 0) (point))
+                        (point))
+      (current-column))))
 
 (defun company--row (&optional pos)
   (save-excursion

commit 11bbdcb8cd323f4a22793a4ded61c8c3e3396aec
Author: Dmitry Gutov <address@hidden>
Date:   Mon May 20 19:58:09 2013 +0400

    Check in NEWS and tests for the previous commit

diff --git a/NEWS.md b/NEWS.md
index 1c33f7c..e5ad713 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,9 @@
 # History of user-visible changes
 
+## Next
+
+* Works in horizontally scrolled windows.
+
 ## 2013-05-10 (0.6.9)
 
 * `company-capf` respects `:exit-function` completion property.
diff --git a/company-tests.el b/company-tests.el
index 011a5d4..a8bdaa9 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -179,33 +179,23 @@
         (company-call 'open-line 1)
         (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
 
-(defun company-test-pseudo-tooltip-overlay-show ()
-  (save-window-excursion
+(ert-deftest company-pseudo-tooltip-overlay-show ()
+  (with-temp-buffer
+    (save-window-excursion
     (set-window-buffer nil (current-buffer))
     (insert "aaaa\n bb\nccccc\nddd")
     (search-backward "bb")
-    (let ((col-row (company--col-row))
+    (let ((col (company--column))
           (company-candidates-length 2)
           (company-candidates '("123" "45")))
-      (company-pseudo-tooltip-show (cdr col-row) (car col-row) 0)
+      (company-pseudo-tooltip-show (company--row) col 0)
       (let ((ov company-pseudo-tooltip-overlay))
         (should (eq (overlay-get ov 'company-width) 3))
         ;; FIXME: Make it 2?
-        (should (eq (overlay-get ov 'company-height) 10))
-        (should (eq (overlay-get ov 'company-column) (car col-row)))
+        (should (eq (overlay-get ov 'company-height) company-tooltip-limit))
+        (should (eq (overlay-get ov 'company-column) col))
         (should (string= (overlay-get ov 'company-before)
-                         " 123\nc45 c\nddd\n"))))))
-
-(ert-deftest company-pseudo-tooltip-overlay-show ()
-  :tags '(interactive)
-  (with-temp-buffer
-    (company-test-pseudo-tooltip-overlay-show)))
-
-(ert-deftest company-pseudo-tooltip-overlay-show-with-header-line ()
-  :tags '(interactive)
-  (with-temp-buffer
-    (setq header-line-format "foo bar")
-    (company-test-pseudo-tooltip-overlay-show)))
+                         " 123\nc45 c\nddd\n")))))))
 
 ;;; Template
 

commit d21bb454dcfacda8808b596e4bca85a53a99eabf
Author: Dmitry Gutov <address@hidden>
Date:   Mon May 20 19:56:48 2013 +0400

    Calculate row and column using `vertical-motion'
    
    * company--replacement-string: Account for horizontal scrolling.
    * Fixes #22.
    
    Thanks to Eli Zaretskii for suggestions:
    http://lists.gnu.org/archive/html/emacs-devel/2013-05/msg00145.html

diff --git a/company.el b/company.el
index 5b800e4..55e5d1c 100644
--- a/company.el
+++ b/company.el
@@ -571,17 +571,16 @@ keymap during active completions (`company-active-map'):
 (defun company-input-noop ()
   (push 31415926 unread-command-events))
 
-;; Hack:
-;; posn-col-row is incorrect in older Emacsen when line-spacing is set
-(defun company--col-row (&optional pos)
-  (let ((posn (posn-at-point pos)))
-    (cons (car (posn-col-row posn)) (cdr (posn-actual-col-row posn)))))
-
-(defsubst company--column (&optional pos)
-  (car (posn-col-row (posn-at-point pos))))
+(defun company--column (&optional pos)
+  (save-excursion
+    (when pos (goto-char pos))
+    (- (point) (progn (vertical-motion 0) (point)))))
 
-(defsubst company--row (&optional pos)
-  (cdr (posn-actual-col-row (posn-at-point pos))))
+(defun company--row (&optional pos)
+  (save-excursion
+    (when pos (goto-char pos))
+    (count-screen-lines (window-start)
+                        (progn (vertical-motion 0) (point)))))
 
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -1326,10 +1325,20 @@ and invoke the normal binding."
            (and (< evt-row row)
                 (>= evt-row (+ row height)))))))
 
+(defun company--event-col-row (event)
+  (let* ((col-row (posn-actual-col-row (event-start event)))
+         (col (car col-row))
+         (row (cdr col-row)))
+    (incf col (window-hscroll))
+    (and header-line-format
+         (version< "24" emacs-version)
+         (decf row))
+    (cons col row)))
+
 (defun company-select-mouse (event)
   "Select the candidate picked by the mouse."
   (interactive "e")
-  (let ((event-col-row (posn-actual-col-row (event-start event)))
+  (let ((event-col-row (company--event-col-row event))
         (ovl-row (company--row))
         (ovl-height (and company-pseudo-tooltip-overlay
                          (min (overlay-get company-pseudo-tooltip-overlay
@@ -1659,9 +1668,11 @@ Example:
 
 (defun company--replacement-string (lines old column nl &optional align-top)
 
-  (let ((width (length (car lines))))
-    (when (> width (- (window-width) column))
-      (setq column (max 0 (- (window-width) width)))))
+  (let ((width (length (car lines)))
+        (remaining-cols (- (+ (window-width) (window-hscroll))
+                           column)))
+    (when (> width remaining-cols)
+      (decf column (- width remaining-cols))))
 
   (let (new)
     (when align-top
@@ -1745,7 +1756,7 @@ Example:
 ;; show
 
 (defsubst company--window-inner-height ()
-  (let ((edges (window-inside-edges (selected-window))))
+  (let ((edges (window-inside-edges)))
     (- (nth 3 edges) (nth 1 edges))))
 
 (defsubst company--pseudo-tooltip-height ()
@@ -1762,15 +1773,9 @@ Returns a negative number if the tooltip should be 
displayed above point."
   (company-pseudo-tooltip-hide)
   (save-excursion
 
-    (move-to-column 0)
-
     (let* ((height (company--pseudo-tooltip-height))
            above)
 
-      (when (and header-line-format
-                 (version< "24" emacs-version))
-        (decf row))
-
       (when (< height 0)
         (setq row (+ row height -1)
               above t))
@@ -1797,10 +1802,9 @@ Returns a negative number if the tooltip should be 
displayed above point."
         (overlay-put ov 'company-height height)))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
-  (let ((col-row (company--col-row pos)))
-    (when col-row
-      (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
-                                   company-selection))))
+  (let ((row (company--row pos))
+        (col (company--column pos)))
+    (company-pseudo-tooltip-show (1+ row) col company-selection)))
 
 (defun company-pseudo-tooltip-edit (selection)
   (let ((height (overlay-get company-pseudo-tooltip-overlay 'company-height)))

commit 4456662366342b75413e2d7b63a3d229220211f6
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 12 20:53:37 2013 -0400

    Add additional information about what is needed for functional tests.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 8183635..a87d021 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -1,5 +1,9 @@
 ;; Simple functional testing
 ;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
+;;
+;; Note: this functional tests requires that you have python with the
+;; Tornado web server.  See http://www.tornadoweb.org/en/stable/ for
+;; information on aquiring.
 
 (require 'tls)   ;; tests a particular bug we had on emacs 23
 (setq debug-on-error t)

commit c1f2813c30433d642f9a3c73b4be3d1bcbc03c93
Merge: 3baf07a 27d3053
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 12 17:51:58 2013 -0700

    Merge pull request #31 from joebo/master
    
    Fix line endings on windows, for the server.


commit 9b1ed514d64f9adff97f1b3b75023ad7ff743887
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 11 12:09:07 2013 +0400

    Turn on email notifications [ci skip]

diff --git a/.travis.yml b/.travis.yml
index bd24745..cdf55d1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,6 +30,3 @@ before_script:
 
 script:
   make test-batch EMACS=${EMACS}
-
-notifications:
-  email: false

commit 757ae4bcc18549e85b3131664ca3639a759ad162
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 11 12:02:02 2013 +0400

    Set up Travis CI

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bb0a9e0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,24 @@
+# https://github.com/rolandwalker/emacs-travis
+
+language: emacs-lisp
+
+env:
+  matrix:
+    - EMACS=emacs24
+    - EMACS=emacs-snapshot
+
+install:
+  - if [ "$EMACS" = "emacs24" ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs24 emacs24-el;
+    fi
+  - if [ "$EMACS" = "emacs-snapshot" ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs-snapshot &&
+        sudo apt-get install -qq emacs-snapshot-el emacs-snapshot-gtk;
+    fi
+
+script:
+  make test EMACS=${EMACS}
diff --git a/Makefile b/Makefile
index a710a93..f86786f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
 # -*- Makefile -*-
 
+EMACS = emacs
+
 # Compile with noninteractive and relatively clean environment.
 BATCHFLAGS = -batch -q --no-site-file
 
@@ -8,7 +10,7 @@ SRCS = js2-mode.el js2-imenu-extras.el
 OBJS = $(SRCS:.el=.elc)
 
 %.elc: %.el
-       emacs $(BATCHFLAGS) -f batch-byte-compile $^
+       ${EMACS} $(BATCHFLAGS) -f batch-byte-compile $^
 
 all: $(OBJS)
 
@@ -17,8 +19,8 @@ clean:
 
 # custom build (require loads)
 js2-imenu-extras.elc: js2-mode.elc
-       emacs $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el
+       ${EMACS} $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el
 
 test:
-       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/parser.el\
-         -l tests/indent.el -l tests/externs.el -f ert-run-tests-batch
+       ${EMACS} $(BATCHFLAGS) -l js2-mode.el -l tests/parser.el\
+         -l tests/indent.el -l tests/externs.el -f ert-run-tests-batch-and-exit
diff --git a/README.md b/README.md
index c83cc41..9065cdf 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-About
+About [![Build 
Status](https://travis-ci.org/mooz/js2-mode.png?branch=master)](https://travis-ci.org/mooz/js2-mode)
 ======
 
 Improved JavaScript editing mode for GNU Emacs ([description 
here](http://elpa.gnu.org/packages/js2-mode.html)).

commit c50f3d1d9db63bcbea3f02036ee17ab0d7511be0
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 20:00:04 2013 +0400

    Description -> About

diff --git a/README.md b/README.md
index 865eb2e..c83cc41 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-Description
+About
 ======
 
 Improved JavaScript editing mode for GNU Emacs ([description 
here](http://elpa.gnu.org/packages/js2-mode.html)).

commit e48289f90d9b8ffa179a5505970421136ef42150
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 19:55:41 2013 +0400

    Alternat{->iv}ely

diff --git a/js2-mode.el b/js2-mode.el
index 9fd8ba4..812c35b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -51,7 +51,7 @@
 
 ;;   (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
 
-;; Alternately, to install it as a minor mode just for JavaScript linting,
+;; Alternatively, to install it as a minor mode just for JavaScript linting,
 ;; you must add it to the appropriate major-mode hook.  Normally this would be:
 
 ;;   (add-hook 'js-mode-hook 'js2-minor-mode)

commit 5c7e8c516f577c6266b05e8a09d4ca6089295f06
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 19:54:45 2013 +0400

    Fix #102

diff --git a/README.md b/README.md
index d66c69a..865eb2e 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,25 @@
 Description
 ======
 
-An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
+Improved JavaScript editing mode for GNU Emacs ([description 
here](http://elpa.gnu.org/packages/js2-mode.html)).
 
 For some of the latest changes, see [latest user-visible 
changes](https://github.com/mooz/js2-mode/wiki/Latest-user-visible-changes).
 
 Installation
 ======
 
-    $ git clone git://github.com/mooz/js2-mode.git
-    $ cd js2-mode
-    $ emacs --batch -f batch-byte-compile js2-mode.el
+The stable versions are hosted at [GNU ELPA](http://elpa.gnu.org/)
+(<kbd>M-x list-packages</kbd>).
 
-Then put js2-mode.elc into your site-lisp directory.
-
-In your emacs config:
-
-    (autoload 'js2-mode "js2-mode" nil t)
-    (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
-
-See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for
-additional details.
+You can also install the latest development version from
+[Melpa](http://melpa.milkbox.net/#installing).
 
 Emacs 22 and 23
 ===============
 
-This version requires Emacs 24. For a backward compatible version, check out 
the branch [emacs23](https://github.com/mooz/js2-mode/tree/emacs23).
+This version requires Emacs 24. For a backward compatible version,
+check out the branch
+[emacs23](https://github.com/mooz/js2-mode/tree/emacs23).
 
 Bugs
 ====

commit cce396a2885f4b91edb4383d85ecc9e38a7533db
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 19:32:09 2013 +0400

    Prefix all tests with "js2-"

diff --git a/tests/indent.el b/tests/indent.el
index b0d1b31..953b8a6 100644
--- a/tests/indent.el
+++ b/tests/indent.el
@@ -11,7 +11,7 @@
                           (point-min) (point)))))))
 
 (defmacro* js2-deftest-indent (name content &key bind)
-  `(ert-deftest ,name ()
+  `(ert-deftest ,(intern (format "js2-%s" name)) ()
      (let ,(append '((js2-basic-offset 2)
                      (js2-pretty-multiline-declarations t)
                      (inhibit-point-motion-hooks t))
diff --git a/tests/parser.el b/tests/parser.el
index 00b7cff..3c05c4b 100644
--- a/tests/parser.el
+++ b/tests/parser.el
@@ -30,7 +30,7 @@ with `js2-print-tree' and assert the result to be equal to the
 original string.  If SYNTAX-ERROR is passed, expect syntax error
 highlighting substring equal to SYNTAX-ERROR value.
 BIND defines bindings to apply them around the test."
-  `(ert-deftest ,name ()
+  `(ert-deftest ,(intern (format "js2-%s" name)) ()
      (let ,(append bind '((js2-basic-offset 2)))
        (js2-test-parse-string ,code-string :syntax-error ,syntax-error))))
 

commit ba08184a0dfba0b6f988321fa83f0f061ab0b8eb
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 19:28:53 2013 +0400

    Include tests/externs.el in the test target

diff --git a/Makefile b/Makefile
index 36f2cb9..a710a93 100644
--- a/Makefile
+++ b/Makefile
@@ -21,4 +21,4 @@ js2-imenu-extras.elc: js2-mode.elc
 
 test:
        emacs $(BATCHFLAGS) -l js2-mode.el -l tests/parser.el\
-         -l tests/indent.el -f ert-run-tests-batch
+         -l tests/indent.el -l tests/externs.el -f ert-run-tests-batch

commit 3c69aea0c267e7bbadd5e35eb6cab54764c9d91c
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 19:20:11 2013 +0400

    Bump the version date

diff --git a/js2-mode.el b/js2-mode.el
index 6fbb611..9fd8ba4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130307
+;; Version: 20130510
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 

commit 2560f92866a1f15ca393b7ae330d755648b2e786
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 17:42:01 2013 +0400

    Fix #104

diff --git a/js2-mode.el b/js2-mode.el
index f333582..6fbb611 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -858,6 +858,9 @@ Next, you can add a function to `js2-mode-hook' that adds 
additional
 externs appropriate for the specific file, perhaps based on its path.
 These should go in `js2-additional-externs', which is buffer-local.
 
+Third, you can use JSLint's global declaration, as long as
+`js2-include-jslint-globals' is non-nil, which see.
+
 Finally, you can add a function to `js2-post-parse-callbacks',
 which is called after parsing completes, and `js2-mode-ast' is bound to
 the root of the parse tree.  At this stage you can set up an AST
@@ -1106,6 +1109,14 @@ another file, or you've got a potential bug."
   :type 'boolean
   :group 'js2-mode)
 
+(defcustom js2-include-jslint-globals t
+  "Non-nil to include the identifiers from JSLint global
+declaration (see http://www.jslint.com/lint.html#global) in the
+buffer-local externs list.  See `js2-additional-externs' for more
+information."
+  :type 'boolean
+  :group 'js2-mode)
+
 (defvar js2-mode-map
   (let ((map (make-sparse-keymap))
         keys)
@@ -6424,6 +6435,31 @@ it is considered declared."
                 (if (or js2-include-browser-externs js2-include-node-externs)
                     js2-typed-array-externs))))
 
+(defun js2-apply-jslint-globals ()
+  (setq js2-additional-externs
+        (nconc (js2-get-jslint-globals)
+               js2-additional-externs)))
+
+(defun js2-get-jslint-globals ()
+  (loop for node in (js2-ast-root-comments js2-mode-ast)
+        when (and (eq 'block (js2-comment-node-format node))
+                  (save-excursion
+                    (goto-char (js2-node-abs-pos node))
+                    (looking-at "/\\*global ")))
+        append (js2-get-jslint-globals-in
+                (match-end 0)
+                (js2-node-abs-end node))))
+
+(defun js2-get-jslint-globals-in (beg end)
+  (let (res)
+    (save-excursion
+      (goto-char beg)
+      (while (re-search-forward js2-mode-identifier-re end t)
+        (let ((match (match-string 0)))
+          (unless (member match '("true" "false"))
+            (push match res)))))
+    (nreverse res)))
+
 ;;; IMenu support
 
 ;; We currently only support imenu, but eventually should support speedbar and
@@ -10074,6 +10110,8 @@ highlighting features of `js2-mode'."
   (set (make-local-variable 'js2-highlight-level) 0) ; no syntax highlighting
   (add-hook 'after-change-functions #'js2-minor-mode-edit nil t)
   (add-hook 'change-major-mode-hook #'js2-minor-mode-exit nil t)
+  (when js2-include-jslint-globals
+    (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
   (js2-reparse))
 
 (defun js2-minor-mode-exit ()
@@ -10085,6 +10123,7 @@ highlighting features of `js2-mode'."
     (delete-overlay js2-mode-node-overlay)
     (setq js2-mode-node-overlay nil))
   (js2-remove-overlays)
+  (remove-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals t)
   (setq js2-mode-ast nil))
 
 (defvar js2-source-buffer nil "Linked source buffer for diagnostics view")
@@ -10265,7 +10304,12 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
         js2-mode-comments-hidden nil
         js2-mode-buffer-dirty-p t
         js2-mode-parsing nil)
+
   (js2-set-default-externs)
+
+  (when js2-include-jslint-globals
+    (add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-globals nil t))
+
   (js2-reparse))
 
 (defun js2-mode-exit ()
diff --git a/tests/externs.el b/tests/externs.el
new file mode 100644
index 0000000..7860058
--- /dev/null
+++ b/tests/externs.el
@@ -0,0 +1,22 @@
+(require 'ert)
+(require 'js2-mode)
+
+(ert-deftest js2-finds-jslint-globals ()
+  (with-temp-buffer
+    (insert "/*global foo, bar:false, baz: true */")
+    (js2-mode)
+    (should (equal (js2-get-jslint-globals)
+                   '("foo" "bar" "baz")))))
+
+(ert-deftest js2-no-jslint-globals-without-keyword ()
+  (with-temp-buffer
+    (insert "/* foo, bar:false, baz: true */")
+    (js2-mode)
+    (should (null (js2-get-jslint-globals)))))
+
+(ert-deftest js2-finds-jslint-globals-in-other-comments ()
+  (with-temp-buffer
+    (insert "/* foo, bar */\n\n\n/*global quux, tee: true, $*/")
+    (js2-mode)
+    (should (equal (js2-get-jslint-globals)
+                   '("quux" "tee" "$")))))

commit 0d1b276e2240bb765908c895cbce862f9a54b9d4
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 16:30:40 2013 +0400

    js2-auto-insert-catch-block: Unused, remove

diff --git a/js2-mode.el b/js2-mode.el
index f7efc53..f333582 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1106,11 +1106,6 @@ another file, or you've got a potential bug."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-auto-insert-catch-block t
-  "Non-nil to insert matching catch block on open-curly after `try'."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defvar js2-mode-map
   (let ((map (make-sparse-keymap))
         keys)

commit 068a36adff25e244dcbb21aafb953fc3b66c5853
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 16:16:48 2013 +0400

    js2-imenu-extras: Define a minor mode
    
    js2-do-parse: Use `run-hooks' on `js2-post-parse-callbacks'.
    js2-post-parse-callbacks: Use `add-hook'.
    
    The old way to set up this should still work, too.

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 3061905..e8e15a5 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -1,5 +1,7 @@
 ;;; js2-imenu-extras.el --- Imenu support for additional constructs
 
+;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
+
 ;; Author:    Dmitry Gutov <address@hidden>
 ;; Keywords:  languages, javascript, imenu
 
@@ -21,14 +23,11 @@
 ;;; Commentary:
 
 ;; This package adds Imenu support for additional framework constructs and
-;; general patterns to `js2-mode'.
+;; structural patterns to `js2-mode'.
 
 ;; Usage:
 
-;; (eval-after-load 'js2-mode
-;;   '(progn
-;;      (require 'js2-imenu-extras)
-;;      (js2-imenu-extras-setup)))
+;; (add-hook 'js2-mode-hook 'js2-imenu-extras-mode)
 
 ;; To customize how it works:
 ;;   M-x customize-group RET js2-imenu RET
@@ -100,9 +99,13 @@ prefix any functions defined inside the IIFE with the 
module name."
 ;;;###autoload
 (defun js2-imenu-extras-setup ()
   (when js2-imenu-enabled-frameworks
-    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
+    (add-hook 'js2-post-parse-callbacks 'js2-imenu-record-declarations t t))
   (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
-    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))
+    (add-hook 'js2-post-parse-callbacks 'js2-imenu-walk-ast t t)))
+
+(defun js2-imenu-extras-remove ()
+  (remove-hook 'js2-post-parse-callbacks 'js2-imenu-record-declarations t)
+  (remove-hook 'js2-post-parse-callbacks 'js2-imenu-walk-ast t))
 
 (defun js2-imenu-record-declarations ()
   (let* ((styles (loop for style in js2-imenu-extension-styles
@@ -208,4 +211,12 @@ NODE must be `js2-assign-node'."
                 (js2-record-imenu-entry fn target-qname
                                         (js2-node-abs-pos target))))))))))
 
+;;;###autoload
+(define-minor-mode js2-imenu-extras-mode
+  "Toggle Imenu support for frameworks and structural patterns."
+  :lighter ""
+  (if js2-imenu-extras-mode
+      (js2-imenu-extras-setup)
+    (js2-imenu-extras-remove)))
+
 (provide 'js2-imenu-extras)
diff --git a/js2-mode.el b/js2-mode.el
index b489458..f7efc53 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7136,8 +7136,7 @@ Scanner should be initialized."
     ;; Give extensions a chance to muck with things before highlighting starts.
     (let ((js2-additional-externs js2-additional-externs))
       (save-excursion
-        (dolist (callback js2-post-parse-callbacks)
-          (funcall callback)))
+        (run-hooks 'js2-post-parse-callbacks))
       (js2-highlight-undeclared-vars))
     root))
 

commit 4c735454d91f9674da0ecea950504888b1e10ff7
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 00:19:59 2013 +0400

    Release 0.6.9

diff --git a/NEWS.md b/NEWS.md
index d8a0c91..1c33f7c 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,7 +1,8 @@
 # History of user-visible changes
 
-## Next
+## 2013-05-10 (0.6.9)
 
+* `company-capf` respects `:exit-function` completion property.
 * `company-backends`: `prefix` command can return `t` in the cdr.
 * `company-clang-begin-after-member-access`: New option.
 * Mouse click outside the tooltip aborts completion.
diff --git a/company.el b/company.el
index 4328924..5b800e4 100644
--- a/company.el
+++ b/company.el
@@ -4,9 +4,9 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.8
+;; Version: 0.6.9
 ;; Keywords: abbrev, convenience, matching
-;; URL: http://company-mode.github.com/
+;; URL: http://company-mode.github.io/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
 
 ;; This file is part of GNU Emacs.

commit 41b1eea33bf85095a2211e8963b0b307ce20147f
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 10 00:16:07 2013 +0400

    Make 'make test' work when the test file is compiled

diff --git a/company-tests.el b/company-tests.el
index 7ff9889..011a5d4 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -25,6 +25,7 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl))
 (require 'ert)
 (require 'company)
 (require 'company-keywords)

commit 409bc6a7d16a9edc3337b90ca878acc3f1e3ae17
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 23:17:58 2013 +0400

    Add Stefan's email

diff --git a/company-capf.el b/company-capf.el
index e614cb0..60e4494 100644
--- a/company-capf.el
+++ b/company-capf.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
-;; Author: Stefan Monnier
+;; Author: Stefan Monnier <address@hidden>
 
 ;; This file is part of GNU Emacs.
 

commit 4508b7a70e18da25d20cc2ac471086fdd51acf2a
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 23:16:55 2013 +0400

    company-capf: Change `require-match' comment

diff --git a/company-capf.el b/company-capf.el
index 455e992..e614cb0 100644
--- a/company-capf.el
+++ b/company-capf.el
@@ -66,7 +66,7 @@ Requires Emacs 24.1 or newer."
     (meta nil)           ;FIXME: Return one-line docstring for `arg'.
     (doc-buffer nil)     ;FIXME: Return help buffer for `arg'.
     (location nil)       ;FIXME: Return (BUF . POS) or (FILE . LINENB) of 
`arg'.
-    (require-match nil)  ;This should be a property of the front-end!
+    (require-match nil)  ;Front-ends should also have a say in this.
     (init nil)       ;Don't bother: plenty of other ways to initialize the 
code.
     (post-completion
      (let* ((res (company--capf-data))

commit 1331b718431597d4dcf2bf432ec642b456fe408b
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 23:14:31 2013 +0400

    Move company-capf to a separate file

diff --git a/company-capf.el b/company-capf.el
new file mode 100644
index 0000000..455e992
--- /dev/null
+++ b/company-capf.el
@@ -0,0 +1,80 @@
+;;; company-capf.el --- company-mode completion-at-point-functions back-end 
-*- lexical-binding: t -*-
+
+;; Copyright (C) 2013  Free Software Foundation, Inc.
+
+;; Author: Stefan Monnier
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
+
+(defun company--capf-data ()
+  (let ((data (run-hook-wrapped 'completion-at-point-functions
+                                ;; Ignore misbehaving functions.
+                                #'completion--capf-wrapper 'optimist)))
+    (when (consp data) data)))
+
+(defun company-capf (command &optional arg &rest _args)
+  "`company-mode' back-end using `completion-at-point-functions'.
+Requires Emacs 24.1 or newer."
+  (interactive (list 'interactive))
+  (case command
+    (interactive (company-begin-backend 'company-capf))
+    (prefix
+     (let ((res (company--capf-data)))
+       (when res
+         (if (> (nth 2 res) (point))
+             'stop
+           (buffer-substring-no-properties (nth 1 res) (point))))))
+    (candidates
+     (let ((res (company--capf-data)))
+       (when res
+         (let* ((table (nth 3 res))
+                (pred (plist-get (nthcdr 4 res) :predicate))
+                (meta (completion-metadata
+                       (buffer-substring (nth 1 res) (nth 2 res))
+                       table pred))
+                (sortfun (cdr (assq 'display-sort-function meta)))
+                (candidates (all-completions arg table pred)))
+           (if sortfun (funcall sortfun candidates) candidates)))))
+    (sorted
+     (let ((res (company--capf-data)))
+       (when res
+         (let ((meta (completion-metadata
+                      (buffer-substring (nth 1 res) (nth 2 res))
+                      (nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
+           (cdr (assq 'display-sort-function meta))))))
+    (duplicates nil)     ;Don't bother.
+    (no-cache t)         ;FIXME: Improve!
+    (meta nil)           ;FIXME: Return one-line docstring for `arg'.
+    (doc-buffer nil)     ;FIXME: Return help buffer for `arg'.
+    (location nil)       ;FIXME: Return (BUF . POS) or (FILE . LINENB) of 
`arg'.
+    (require-match nil)  ;This should be a property of the front-end!
+    (init nil)       ;Don't bother: plenty of other ways to initialize the 
code.
+    (post-completion
+     (let* ((res (company--capf-data))
+            (exit-function (plist-get (nthcdr 4 res) :exit-function)))
+       (if exit-function
+           (funcall exit-function arg 'finished))))
+    ))
+
+(provide 'company-capf)
+
+;;; company-capf.el ends here
diff --git a/company.el b/company.el
index 2bd6114..4328924 100644
--- a/company.el
+++ b/company.el
@@ -213,6 +213,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
 
 (defvar company-safe-backends
   '((company-abbrev . "Abbrev")
+    (company-capf . "completion-at-point-functions")
     (company-clang . "Clang")
     (company-css . "CSS")
     (company-dabbrev . "dabbrev for plain text")
@@ -241,56 +242,6 @@ If this many lines are not available, prefer to display 
the tooltip above."
                         (assq backend company-safe-backends))
                 (return t))))))
 
-(defun company--capf-data ()
-  (let ((data (run-hook-wrapped 'completion-at-point-functions
-                                ;; Ignore misbehaving functions.
-                                #'completion--capf-wrapper 'optimist)))
-    (when (consp data) data)))
-
-(defun company-capf (command &optional arg &rest _args)
-  "`company-mode' back-end using `completion-at-point-functions'.
-Requires Emacs 24.1 or newer."
-  (interactive (list 'interactive))
-  (case command
-    (interactive (company-begin-backend 'company-capf))
-    (prefix
-     (let ((res (company--capf-data)))
-       (when res
-         (if (> (nth 2 res) (point))
-             'stop
-           (buffer-substring-no-properties (nth 1 res) (point))))))
-    (candidates
-     (let ((res (company--capf-data)))
-       (when res
-         (let* ((table (nth 3 res))
-                (pred (plist-get (nthcdr 4 res) :predicate))
-                (meta (completion-metadata
-                      (buffer-substring (nth 1 res) (nth 2 res))
-                      table pred))
-                (sortfun (cdr (assq 'display-sort-function meta)))
-                (candidates (all-completions arg table pred)))
-           (if sortfun (funcall sortfun candidates) candidates)))))
-    (sorted
-     (let ((res (company--capf-data)))
-       (when res
-         (let ((meta (completion-metadata
-                      (buffer-substring (nth 1 res) (nth 2 res))
-                      (nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
-           (cdr (assq 'display-sort-function meta))))))
-    (duplicates nil) ;Don't bother.
-    (no-cache t)     ;FIXME: Improve!
-    (meta nil)       ;FIXME: Return one-line docstring for `arg'.
-    (doc-buffer nil) ;FIXME: Return help buffer for `arg'.
-    (location nil)   ;FIXME: Return (BUF . POS) or (FILE . LINENB) of `arg'.
-    (require-match nil)            ;This should be a property of the front-end!
-    (init nil)      ;Don't bother: plenty of other ways to initialize the code.
-    (post-completion
-     (let* ((res (company--capf-data))
-            (exit-function (plist-get (nthcdr 4 res) :exit-function)))
-       (if exit-function
-           (funcall exit-function arg 'finished))))
-    ))
-
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-clang company-eclim
                               company-xcode company-ropemacs

commit 3d7683107180203654e0da80ed556240bc94c2b3
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 22:46:26 2013 +0400

    Fix some more compilation warnings

diff --git a/company-eclim.el b/company-eclim.el
index 864f550..ea0b73e 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -69,6 +69,8 @@ eclim can only complete correctly when the buffer has been 
saved."
 (defvar company-eclim--doc nil)
 (make-variable-buffer-local 'company-eclim--doc)
 
+(declare-function json-read "json")
+
 (defun company-eclim--call-process (&rest args)
   (let ((coding-system-for-read 'utf-8)
         res)
diff --git a/company-elisp.el b/company-elisp.el
index b55ed9f..5bfc27e 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -111,7 +111,7 @@ first in the candidates list."
         res)
     (condition-case nil
         (save-excursion
-          (dotimes (i company-elisp-parse-depth)
+          (dotimes (_ company-elisp-parse-depth)
             (up-list -1)
             (save-excursion
               (when (eq (char-after) ?\()
@@ -126,7 +126,7 @@ first in the candidates list."
                                   company-elisp-var-binding-regexp))
                     (down-list 1)
                     (condition-case nil
-                        (dotimes (i company-elisp-parse-limit)
+                        (dotimes (_ company-elisp-parse-limit)
                           (save-excursion
                             (when (looking-at "[ \t\n]*(")
                               (down-list 1))
diff --git a/company-tests.el b/company-tests.el
index 9b8e914..7ff9889 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -28,6 +28,8 @@
 (require 'ert)
 (require 'company)
 (require 'company-keywords)
+(require 'company-elisp)
+(require 'company-clang)
 
 ;;; Core
 
diff --git a/company.el b/company.el
index 2625e2a..2bd6114 100644
--- a/company.el
+++ b/company.el
@@ -1357,6 +1357,10 @@ and invoke the normal binding."
     (company-abort)
     (company--unread-last-input)))
 
+(defvar company-pseudo-tooltip-overlay)
+
+(defvar company-tooltip-offset)
+
 (defun company--inside-tooltip-p (event-col-row row height)
   (let* ((ovl company-pseudo-tooltip-overlay)
          (column (overlay-get ovl 'company-column))

commit 837c8899e6957a9acbd058d3c3d92bc165956f07
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 21:54:33 2013 +0400

    Add compile target

diff --git a/Makefile b/Makefile
index ff1dc3e..f11b04e 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ elpa: *.el
        tar cvf company-$$version.tar --mode 644 "$$dir"
 
 clean:
-       @rm -rf company-*/ company-*.tar company-*.tar.bz2
+       @rm -rf company-*/ company-*.tar company-*.tar.bz2 *.elc ert.el
 
 test:
        ${EMACS} -Q -nw -L . -l company-tests.el \
@@ -32,3 +32,6 @@ test-batch:
 downloads:
        ${EMACS} -Q --batch -l ert || \
        ${CURL} ${ERT_URL} > ert.el
+
+compile:
+       ${EMACS} -Q --batch -L . -f batch-byte-compile company.el company-*.el

commit f480808a73a2e60c2480bd89825d0af60b75b9fb
Author: Stefan Monnier <address@hidden>
Date:   Thu May 9 10:43:37 2013 +0400

    * company.el (company-capf): Add support for `sorted' and `post-completion'.
      (company--capf-data): New function.
      (company-backend): Declare before first use.
      (company-require-match-p): Only call company-require-match when needed.
      (company--continue-failed): Don't use backward-delete-char 
non-interactively.
      (company-search-assert-enabled): Demote it, since it comes too late to
      be inlined.
      (company--replacement-string, company--create-lines)
      (company-pseudo-tooltip-edit, company-doc-buffer): Silence the 
byte-compiler.

diff --git a/company.el b/company.el
index 824af82..2625e2a 100644
--- a/company.el
+++ b/company.el
@@ -71,6 +71,7 @@
 
 (eval-when-compile (require 'cl))
 
+;; FIXME: Use `user-error'.
 (add-to-list 'debug-ignored-errors "^.* frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^No \\(document\\|loc\\)ation available$")
@@ -171,16 +172,16 @@
 Each front-end is a function that takes one argument.  It is called with
 one of the following arguments:
 
-'show: When the visualization should start.
+`show': When the visualization should start.
 
-'hide: When the visualization should end.
+`hide': When the visualization should end.
 
-'update: When the data has been updated.
+`update': When the data has been updated.
 
-'pre-command: Before every command that is executed while the
+`pre-command': Before every command that is executed while the
 visualization is active.
 
-'post-command: After every command that is executed while the
+`post-command': After every command that is executed while the
 visualization is active.
 
 The visualized data is stored in `company-prefix', `company-candidates',
@@ -240,27 +241,55 @@ If this many lines are not available, prefer to display 
the tooltip above."
                         (assq backend company-safe-backends))
                 (return t))))))
 
-(defun company-capf (command &optional arg &rest args)
+(defun company--capf-data ()
+  (let ((data (run-hook-wrapped 'completion-at-point-functions
+                                ;; Ignore misbehaving functions.
+                                #'completion--capf-wrapper 'optimist)))
+    (when (consp data) data)))
+
+(defun company-capf (command &optional arg &rest _args)
   "`company-mode' back-end using `completion-at-point-functions'.
 Requires Emacs 24.1 or newer."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-capf))
     (prefix
-     (let ((res (run-hook-wrapped 'completion-at-point-functions
-                                  ;; Ignore misbehaving functions.
-                                  #'completion--capf-wrapper 'optimist)))
-       (when (consp res)
+     (let ((res (company--capf-data)))
+       (when res
          (if (> (nth 2 res) (point))
              'stop
            (buffer-substring-no-properties (nth 1 res) (point))))))
     (candidates
-     (let ((res (run-hook-wrapped 'completion-at-point-functions
-                                  ;; Ignore misbehaving functions.
-                                  #'completion--capf-wrapper 'optimist)))
-       (when (consp res)
-         (all-completions arg (nth 3 res)
-                          (plist-get (nthcdr 4 res) :predicate)))))))
+     (let ((res (company--capf-data)))
+       (when res
+         (let* ((table (nth 3 res))
+                (pred (plist-get (nthcdr 4 res) :predicate))
+                (meta (completion-metadata
+                      (buffer-substring (nth 1 res) (nth 2 res))
+                      table pred))
+                (sortfun (cdr (assq 'display-sort-function meta)))
+                (candidates (all-completions arg table pred)))
+           (if sortfun (funcall sortfun candidates) candidates)))))
+    (sorted
+     (let ((res (company--capf-data)))
+       (when res
+         (let ((meta (completion-metadata
+                      (buffer-substring (nth 1 res) (nth 2 res))
+                      (nth 3 res) (plist-get (nthcdr 4 res) :predicate))))
+           (cdr (assq 'display-sort-function meta))))))
+    (duplicates nil) ;Don't bother.
+    (no-cache t)     ;FIXME: Improve!
+    (meta nil)       ;FIXME: Return one-line docstring for `arg'.
+    (doc-buffer nil) ;FIXME: Return help buffer for `arg'.
+    (location nil)   ;FIXME: Return (BUF . POS) or (FILE . LINENB) of `arg'.
+    (require-match nil)            ;This should be a property of the front-end!
+    (init nil)      ;Don't bother: plenty of other ways to initialize the code.
+    (post-completion
+     (let* ((res (company--capf-data))
+            (exit-function (plist-get (nthcdr 4 res) :exit-function)))
+       (if exit-function
+           (funcall exit-function arg 'finished))))
+    ))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-clang company-eclim
@@ -281,8 +310,8 @@ The first argument is the command requested from the 
back-end.  It is one
 of the following:
 
 `prefix': The back-end should return the text to be completed.  It must be text
-immediately before `point'.  Returning nil passes control to the next back-end.
-The function should return 'stop if it should complete but cannot \(e.g. if it
+immediately before point.  Returning nil passes control to the next back-end.
+The function should return `stop' if it should complete but cannot \(e.g. if it
 is in the middle of a string\).  Instead of a string, the back-end may return a
 cons where car is the prefix and cdr is used in `company-minimum-prefix-length'
 test. It's either number or t, in which case the test automatically succeeds.
@@ -372,8 +401,8 @@ consider using the `post-completion' command instead."
   "If enabled, disallow non-matching input.
 This can be a function do determine if a match is required.
 
-This can be overridden by the back-end, if it returns t or 'never to
-'require-match.  `company-auto-complete' also takes precedence over this."
+This can be overridden by the back-end, if it returns t or `never' to
+`require-match'.  `company-auto-complete' also takes precedence over this."
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
                  (const :tag "On, if user interaction took place"
@@ -605,6 +634,9 @@ keymap during active completions (`company-active-map'):
 
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(defvar company-backend nil)
+(make-variable-buffer-local 'company-backend)
+
 (defun company-grab (regexp &optional expression limit)
   (when (looking-back regexp limit)
     (or (match-string-no-properties (or expression 0)) "")))
@@ -670,9 +702,6 @@ keymap during active completions (`company-active-map'):
 
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-backend nil)
-(make-variable-buffer-local 'company-backend)
-
 (defvar company-prefix nil)
 (make-variable-buffer-local 'company-prefix)
 
@@ -895,10 +924,10 @@ can retrieve meta-data for them."
 (defun company-require-match-p ()
   (let ((backend-value (company-call-backend 'require-match)))
     (or (eq backend-value t)
-        (and (if (functionp company-require-match)
+        (and (not (eq backend-value 'never))
+             (if (functionp company-require-match)
                  (funcall company-require-match)
-               (eq company-require-match t))
-             (not (eq backend-value 'never))))))
+               (eq company-require-match t))))))
 
 (defun company-auto-complete-p (input)
   "Return non-nil, if input starts with punctuation or parentheses."
@@ -938,7 +967,7 @@ can retrieve meta-data for them."
        ((and (company--string-incremental-p company-prefix new-prefix)
              (company-require-match-p))
         ;; wrong incremental input, but required match
-        (backward-delete-char (length input))
+        (delete-char (- (length input)))
         (ding)
         (message "Matching input is required")
         company-candidates)
@@ -1258,7 +1287,7 @@ Don't start this directly, use 
`company-search-candidates' or
     (kill-local-variable 'company-search-old-selection)
     (company-enable-overriding-keymap company-active-map)))
 
-(defsubst company-search-assert-enabled ()
+(defun company-search-assert-enabled ()
   (company-assert-enabled)
   (unless company-search-mode
     (company-uninstall-map)
@@ -1456,7 +1485,7 @@ To show the number next to the candidates in some 
back-ends, enable
             (cons selected (company-call-backend 'meta selected))))
     (cdr company-last-metadata)))
 
-(defun company-doc-buffer (&optional string)
+(defun company-doc-buffer (&optional _string)
   (with-current-buffer (get-buffer-create "*Company meta-data*")
     (erase-buffer)
     (current-buffer)))
@@ -1561,6 +1590,8 @@ completes the input.
 
 Example:
 \(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
+  ;; FIXME: When Emacs 23 is no longer a concern, replace
+  ;; `company-begin-with-marker' with a lexical variable; use a lexical 
closure.
   (setq company-begin-with-marker (copy-marker (point) t))
   (company-begin-backend
    `(lambda (command &optional arg &rest ignored)
@@ -1680,7 +1711,7 @@ Example:
   (let (new)
     (when align-top
       ;; untouched lines first
-      (dotimes (i (- (length old) (length lines)))
+      (dotimes (_ (- (length old) (length lines)))
         (push (pop old) new)))
     ;; length into old lines.
     (while old
@@ -1722,7 +1753,7 @@ Example:
           len (min limit len)
           lines-copy lines)
 
-    (dotimes (i len)
+    (dotimes (_ len)
       (setq width (max (length (pop lines-copy)) width)))
     (setq width (min width (window-width)))
 
@@ -1816,7 +1847,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
       (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
                                    company-selection))))
 
-(defun company-pseudo-tooltip-edit (lines selection)
+(defun company-pseudo-tooltip-edit (selection)
   (let ((height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (apply 'company--replacement-string
@@ -1871,8 +1902,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (hide (company-pseudo-tooltip-hide)
           (setq company-tooltip-offset 0))
     (update (when (overlayp company-pseudo-tooltip-overlay)
-              (company-pseudo-tooltip-edit company-candidates
-                                           company-selection)))))
+              (company-pseudo-tooltip-edit company-selection)))))
 
 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
   "`company-pseudo-tooltip-frontend', but not shown for single candidates."

commit d159a22470d500c7095261266e7bff9139bac2fb
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 08:22:59 2013 +0400

    emacs22 fails to install

diff --git a/.travis.yml b/.travis.yml
index a717d57..bd24745 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,24 +4,11 @@ language: emacs-lisp
 
 env:
   matrix:
-    - EMACS=emacs22
     - EMACS=emacs23
     - EMACS=emacs24
     - EMACS=emacs-snapshot
 
 install:
-  - if [ "$EMACS" = "emacs22" ]; then
-        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22_22.2-0ubuntu9_i386.deb
 &&
-        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-bin-common_22.2-0ubuntu9_i386.deb
 &&
-        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-common_22.2-0ubuntu9_all.deb
 &&
-        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-el_22.2-0ubuntu9_all.deb
 &&
-        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-gtk_22.2-0ubuntu9_i386.deb
 &&
-        sudo apt-get update -qq &&
-        sudo apt-get remove -qq emacs emacs23-bin-common emacs23-common 
emacs23-nox &&
-        sudo apt-get install -qq libjpeg62 xaw3dg &&
-        sudo dpkg -i emacs22_22.2-0ubuntu9_i386.deb 
emacs22-bin-common_22.2-0ubuntu9_i386.deb emacs22-common_22.2-0ubuntu9_all.deb 
emacs22-el_22.2-0ubuntu9_all.deb emacs22-gtk_22.2-0ubuntu9_i386.deb &&
-        sudo update-alternatives --set emacs22 /usr/bin/emacs22-gtk;
-    fi
   - if [ "$EMACS" = "emacs23" ]; then
         sudo apt-get update -qq &&
         sudo apt-get install -qq emacs23-gtk emacs23-el;

commit 2e9af64d0fb19dda43da7ed90df825f3b231d6d4
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 08:12:07 2013 +0400

    ERT window should occupy the whole frame

diff --git a/Makefile b/Makefile
index 6da5117..ff1dc3e 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,8 @@ clean:
        @rm -rf company-*/ company-*.tar company-*.tar.bz2
 
 test:
-       ${EMACS} -Q -nw -L . -l company-tests.el --eval "(ert t)"
+       ${EMACS} -Q -nw -L . -l company-tests.el \
+       --eval "(let (pop-up-windows) (ert t))"
 
 test-batch:
        ${EMACS} -Q --batch -L . -l company-tests.el \
diff --git a/company-tests.el b/company-tests.el
index 7478918..9b8e914 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -182,14 +182,13 @@
     (insert "aaaa\n bb\nccccc\nddd")
     (search-backward "bb")
     (let ((col-row (company--col-row))
-          (company-tooltip-limit 5)
           (company-candidates-length 2)
           (company-candidates '("123" "45")))
       (company-pseudo-tooltip-show (cdr col-row) (car col-row) 0)
       (let ((ov company-pseudo-tooltip-overlay))
         (should (eq (overlay-get ov 'company-width) 3))
         ;; FIXME: Make it 2?
-        (should (eq (overlay-get ov 'company-height) 5))
+        (should (eq (overlay-get ov 'company-height) 10))
         (should (eq (overlay-get ov 'company-column) (car col-row)))
         (should (string= (overlay-get ov 'company-before)
                          " 123\nc45 c\nddd\n"))))))

commit 0a0e8c6fec890b2ce9823da234f7668e55162987
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 08:09:03 2013 +0400

    Decrease company-tooltip-limit in test
    
    Less likely to fail in smaller terminal window.

diff --git a/company-tests.el b/company-tests.el
index 9b8e914..7478918 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -182,13 +182,14 @@
     (insert "aaaa\n bb\nccccc\nddd")
     (search-backward "bb")
     (let ((col-row (company--col-row))
+          (company-tooltip-limit 5)
           (company-candidates-length 2)
           (company-candidates '("123" "45")))
       (company-pseudo-tooltip-show (cdr col-row) (car col-row) 0)
       (let ((ov company-pseudo-tooltip-overlay))
         (should (eq (overlay-get ov 'company-width) 3))
         ;; FIXME: Make it 2?
-        (should (eq (overlay-get ov 'company-height) 10))
+        (should (eq (overlay-get ov 'company-height) 5))
         (should (eq (overlay-get ov 'company-column) (car col-row)))
         (should (string= (overlay-get ov 'company-before)
                          " 123\nc45 c\nddd\n"))))))

commit a254018f99467ad86d0bd6a798b9ef88ca92e371
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:54:52 2013 +0400

    Add build status badge

diff --git a/README.md b/README.md
index 5501ec2..4f79bbc 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,4 @@
 See the [homepage](http://company-mode.github.com/).
 [![githalytics.com 
alpha](https://cruel-carlota.pagodabox.com/336ef4be2595a7859d52e2c17b7da2b2 
"githalytics.com")](http://githalytics.com/company-mode/company-mode)
+
+[![Build 
Status](https://travis-ci.org/company-mode/company-mode.png?branch=master)](https://travis-ci.org/company-mode/company-mode)

commit 5e0b93a40db3299f32ff6861906067ae7f881607
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:51:52 2013 +0400

    Use emacs -L argument

diff --git a/Makefile b/Makefile
index 20c472e..6da5117 100644
--- a/Makefile
+++ b/Makefile
@@ -22,13 +22,11 @@ clean:
        @rm -rf company-*/ company-*.tar company-*.tar.bz2
 
 test:
-       ${EMACS} -Q -nw --eval "(add-to-list 'load-path \".\")" \
-       -l company-tests.el --eval "(ert t)"
+       ${EMACS} -Q -nw -L . -l company-tests.el --eval "(ert t)"
 
 test-batch:
-       ${EMACS} -Q --batch --eval "(add-to-list 'load-path \".\")" \
-       -l company-tests.el --eval "(ert-run-tests-batch-and-exit \
-         '(not (tag interactive)))"
+       ${EMACS} -Q --batch -L . -l company-tests.el \
+       --eval "(ert-run-tests-batch-and-exit '(not (tag interactive)))"
 
 downloads:
        ${EMACS} -Q --batch -l ert || \

commit f06ba5a6a919049f169d7507433b8f4f85b5b90c
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:38:53 2013 +0400

    Use stable URL for ERT

diff --git a/Makefile b/Makefile
index a4bebd1..20c472e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 EMACS=emacs
 CURL=curl --silent
-ERT_URL=http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/ert.el
+ERT_URL=http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/ert.el?h=emacs-24
 
 .PHONY: ert test test-batch
 

commit 6e37b4c18e63464a544941f6968a4b063b4eb16b
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:33:33 2013 +0400

    Add a backslash

diff --git a/Makefile b/Makefile
index f95e01e..a4bebd1 100644
--- a/Makefile
+++ b/Makefile
@@ -31,5 +31,5 @@ test-batch:
          '(not (tag interactive)))"
 
 downloads:
-       ${EMACS} -Q --batch -l ert ||
+       ${EMACS} -Q --batch -l ert || \
        ${CURL} ${ERT_URL} > ert.el

commit dea7474d33b5164c40cee3e557eb287913da566f
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:26:55 2013 +0400

    Try the new travis.yml

diff --git a/.gitignore b/.gitignore
index c531d98..2ecd291 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 *.elc
+ert.el
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..a717d57
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,48 @@
+# https://github.com/rolandwalker/emacs-travis
+
+language: emacs-lisp
+
+env:
+  matrix:
+    - EMACS=emacs22
+    - EMACS=emacs23
+    - EMACS=emacs24
+    - EMACS=emacs-snapshot
+
+install:
+  - if [ "$EMACS" = "emacs22" ]; then
+        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22_22.2-0ubuntu9_i386.deb
 &&
+        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-bin-common_22.2-0ubuntu9_i386.deb
 &&
+        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-common_22.2-0ubuntu9_all.deb
 &&
+        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-el_22.2-0ubuntu9_all.deb
 &&
+        curl -Os 
http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-gtk_22.2-0ubuntu9_i386.deb
 &&
+        sudo apt-get update -qq &&
+        sudo apt-get remove -qq emacs emacs23-bin-common emacs23-common 
emacs23-nox &&
+        sudo apt-get install -qq libjpeg62 xaw3dg &&
+        sudo dpkg -i emacs22_22.2-0ubuntu9_i386.deb 
emacs22-bin-common_22.2-0ubuntu9_i386.deb emacs22-common_22.2-0ubuntu9_all.deb 
emacs22-el_22.2-0ubuntu9_all.deb emacs22-gtk_22.2-0ubuntu9_i386.deb &&
+        sudo update-alternatives --set emacs22 /usr/bin/emacs22-gtk;
+    fi
+  - if [ "$EMACS" = "emacs23" ]; then
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs23-gtk emacs23-el;
+    fi
+  - if [ "$EMACS" = "emacs24" ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs24 emacs24-el;
+    fi
+  - if [ "$EMACS" = "emacs-snapshot" ]; then
+        sudo add-apt-repository -y ppa:cassou/emacs &&
+        sudo apt-get update -qq &&
+        sudo apt-get install -qq emacs-snapshot &&
+        sudo apt-get install -qq emacs-snapshot-el emacs-snapshot-gtk;
+    fi
+
+before_script:
+  make downloads
+
+script:
+  make test-batch EMACS=${EMACS}
+
+notifications:
+  email: false
diff --git a/Makefile b/Makefile
index db28faf..f95e01e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,8 @@
 EMACS=emacs
+CURL=curl --silent
+ERT_URL=http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/ert.el
+
+.PHONY: ert test test-batch
 
 package: *.el
        @ver=`grep -o "Version: .*" company.el | cut -c 10-`; \
@@ -25,3 +29,7 @@ test-batch:
        ${EMACS} -Q --batch --eval "(add-to-list 'load-path \".\")" \
        -l company-tests.el --eval "(ert-run-tests-batch-and-exit \
          '(not (tag interactive)))"
+
+downloads:
+       ${EMACS} -Q --batch -l ert ||
+       ${CURL} ${ERT_URL} > ert.el

commit 7d557877cf536db6639f6598bcc87001f9f59c11
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 07:05:35 2013 +0400

    company--inside-tooltip-p: Be more precise
    
    when company-candidates-length < overlay's company-height property

diff --git a/company.el b/company.el
index 9e65bd4..824af82 100644
--- a/company.el
+++ b/company.el
@@ -1328,30 +1328,32 @@ and invoke the normal binding."
     (company-abort)
     (company--unread-last-input)))
 
-(defun company--inside-tooltip-p (event-col-row ovl-row)
-  (when company-pseudo-tooltip-overlay
-    (let* ((ovl company-pseudo-tooltip-overlay)
-           (column (overlay-get ovl 'company-column))
-           (width (overlay-get ovl 'company-width))
-           (height (overlay-get ovl 'company-height))
-           (evt-col (car event-col-row))
-           (evt-row (cdr event-col-row)))
-      (and (>= evt-col column)
-           (< evt-col (+ column width))
-           (if (> height 0)
-               (and (> evt-row ovl-row)
-                    (<= evt-row (+ ovl-row height) ))
-             (and (< evt-row ovl-row)
-                  (>= evt-row (+ ovl-row height))))))))
+(defun company--inside-tooltip-p (event-col-row row height)
+  (let* ((ovl company-pseudo-tooltip-overlay)
+         (column (overlay-get ovl 'company-column))
+         (width (overlay-get ovl 'company-width))
+         (evt-col (car event-col-row))
+         (evt-row (cdr event-col-row)))
+    (and (>= evt-col column)
+         (< evt-col (+ column width))
+         (if (> height 0)
+             (and (> evt-row row)
+                  (<= evt-row (+ row height) ))
+           (and (< evt-row row)
+                (>= evt-row (+ row height)))))))
 
 (defun company-select-mouse (event)
   "Select the candidate picked by the mouse."
   (interactive "e")
   (let ((event-col-row (posn-actual-col-row (event-start event)))
-        (ovl-row (company--row)))
-    (if (company--inside-tooltip-p event-col-row ovl-row)
-        (let ((ovl-height (overlay-get company-pseudo-tooltip-overlay
-                                       'company-height)))
+        (ovl-row (company--row))
+        (ovl-height (and company-pseudo-tooltip-overlay
+                         (min (overlay-get company-pseudo-tooltip-overlay
+                                           'company-height)
+                              company-candidates-length))))
+    (if (and ovl-height
+             (company--inside-tooltip-p event-col-row ovl-row ovl-height))
+        (progn
           (company-set-selection (+ (cdr event-col-row)
                                     (if (zerop company-tooltip-offset)
                                         -1

commit 81fc9e178f2a5a15b8253bcc3c70854dc9cd7736
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 06:48:56 2013 +0400

    Fix #21

diff --git a/company-tests.el b/company-tests.el
index 309d8f1..9b8e914 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -160,6 +160,7 @@
       (should (null (company-explicit-action-p))))))
 
 (ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
+  :tags '(interactive)
   (with-temp-buffer
     (save-window-excursion
       (set-window-buffer nil (current-buffer))
@@ -175,6 +176,34 @@
         (company-call 'open-line 1)
         (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
 
+(defun company-test-pseudo-tooltip-overlay-show ()
+  (save-window-excursion
+    (set-window-buffer nil (current-buffer))
+    (insert "aaaa\n bb\nccccc\nddd")
+    (search-backward "bb")
+    (let ((col-row (company--col-row))
+          (company-candidates-length 2)
+          (company-candidates '("123" "45")))
+      (company-pseudo-tooltip-show (cdr col-row) (car col-row) 0)
+      (let ((ov company-pseudo-tooltip-overlay))
+        (should (eq (overlay-get ov 'company-width) 3))
+        ;; FIXME: Make it 2?
+        (should (eq (overlay-get ov 'company-height) 10))
+        (should (eq (overlay-get ov 'company-column) (car col-row)))
+        (should (string= (overlay-get ov 'company-before)
+                         " 123\nc45 c\nddd\n"))))))
+
+(ert-deftest company-pseudo-tooltip-overlay-show ()
+  :tags '(interactive)
+  (with-temp-buffer
+    (company-test-pseudo-tooltip-overlay-show)))
+
+(ert-deftest company-pseudo-tooltip-overlay-show-with-header-line ()
+  :tags '(interactive)
+  (with-temp-buffer
+    (setq header-line-format "foo bar")
+    (company-test-pseudo-tooltip-overlay-show)))
+
 ;;; Template
 
 (ert-deftest company-template-removed-after-the-last-jump ()
diff --git a/company.el b/company.el
index 901aac1..9e65bd4 100644
--- a/company.el
+++ b/company.el
@@ -1779,6 +1779,10 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (let* ((height (company--pseudo-tooltip-height))
            above)
 
+      (when (and header-line-format
+                 (version< "24" emacs-version))
+        (decf row))
+
       (when (< height 0)
         (setq row (+ row height -1)
               above t))

commit c1dd7729321250407f804f0fe26939ea141f6e14
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 9 06:40:06 2013 +0400

    Add test targets

diff --git a/Makefile b/Makefile
index de124c5..db28faf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+EMACS=emacs
+
 package: *.el
        @ver=`grep -o "Version: .*" company.el | cut -c 10-`; \
        tar cjvf company-$$ver.tar.bz2 --mode 644 `git ls-files '*.el' | xargs`
@@ -14,3 +16,12 @@ elpa: *.el
 
 clean:
        @rm -rf company-*/ company-*.tar company-*.tar.bz2
+
+test:
+       ${EMACS} -Q -nw --eval "(add-to-list 'load-path \".\")" \
+       -l company-tests.el --eval "(ert t)"
+
+test-batch:
+       ${EMACS} -Q --batch --eval "(add-to-list 'load-path \".\")" \
+       -l company-tests.el --eval "(ert-run-tests-batch-and-exit \
+         '(not (tag interactive)))"

commit 27d3053993f73460b3ec48f4ae9779577f3c829c
Author: unknown <address@hidden>
Date:   Wed May 8 22:29:40 2013 -0400

    force unix mode so line endings are not converted

diff --git a/websocket.el b/websocket.el
index 8fda4fd..fc53ffd 100644
--- a/websocket.el
+++ b/websocket.el
@@ -842,6 +842,7 @@ connection, which should be kept in order to pass to
              :protocols (process-get server :protocol)
              :extensions (mapcar 'car (process-get server :extensions)))))
     (add-to-list 'websocket-server-websockets ws)
+    (set-process-coding-system client 'unix 'unix)
     (process-put client :websocket ws)
     (set-process-filter client 'websocket-server-filter)
     ;; set-process-filter-multibyte is obsolete, but make-network-process's

commit d4913b4147167bdcde22b44e4f0ec74f265e562d
Author: Dmitry Gutov <address@hidden>
Date:   Mon May 6 16:07:25 2013 +0400

    Update company-clang.el
    
    stardard -> standard

diff --git a/company-clang.el b/company-clang.el
index bdf8ca4..a26c691 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -266,7 +266,7 @@ with `company-clang-set-prefix' or automatically through a 
custom
 `company-clang-prefix-guesser'.
 
 With Clang versions before 2.9, we have to save the buffer before performing
-completion.  With Clang 2.9 and later, buffer contents are passed via stardard
+completion.  With Clang 2.9 and later, buffer contents are passed via standard
 input."
   (interactive (list 'interactive))
   (case command

commit 9add1d8d3339153a5ec121a47e89bfc3ef1b1002
Author: Dmitry Gutov <address@hidden>
Date:   Mon May 6 14:06:00 2013 +0400

    company-clang-begin-after-member-access: include C++'s scope operator

diff --git a/company-clang.el b/company-clang.el
index 6abebe7..bdf8ca4 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -39,10 +39,11 @@
   :type 'file)
 
 (defcustom company-clang-begin-after-member-access t
-  "When non-nil, automatic completion will start whenever the current symbol
-is preceded by \".\" or \"->\", ignoring `company-minimum-prefix-length'.
+  "When non-nil, automatic completion will start whenever the current symbol is
+preceded by \".\", \"->\" or \"::\", ignoring `company-minimum-prefix-length'.
 
-If `company-begin-commands' is a list, it should include `c-electric-lt-gt'.")
+If `company-begin-commands' is a list, it should include `c-electric-lt-gt' and
+`c-electric-colon', for automatic completion right after \">\" and \":\".")
 
 (defcustom company-clang-arguments nil
   "Additional arguments to pass to clang when completing.
@@ -213,7 +214,7 @@ Prefix files (-include ...) can be selected with
         (if (and company-clang-begin-after-member-access
                  (save-excursion
                    (forward-char (- (length symbol)))
-                   (looking-back "\\.\\|->" (- (point) 3))))
+                   (looking-back "\\.\\|->\\|::" (- (point) 2))))
             (cons symbol t)
           symbol)
       'stop)))

commit ac6121486845963000096bec0d81b81742f13702
Author: Dmitry Gutov <address@hidden>
Date:   Mon May 6 10:19:39 2013 +0400

    Close #19

diff --git a/NEWS.md b/NEWS.md
index db8cbe0..d8a0c91 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,8 @@
 
 ## Next
 
+* `company-backends`: `prefix` command can return `t` in the cdr.
+* `company-clang-begin-after-member-access`: New option.
 * Mouse click outside the tooltip aborts completion.
 * `company-clang` uses standard input to pass the contents of current buffer to
   Clang 2.9+, otherwise saves the buffer and passes the path to the file.
diff --git a/company-clang.el b/company-clang.el
index 947afe2..6abebe7 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -38,6 +38,12 @@
   "Location of clang executable."
   :type 'file)
 
+(defcustom company-clang-begin-after-member-access t
+  "When non-nil, automatic completion will start whenever the current symbol
+is preceded by \".\" or \"->\", ignoring `company-minimum-prefix-length'.
+
+If `company-begin-commands' is a list, it should include `c-electric-lt-gt'.")
+
 (defcustom company-clang-arguments nil
   "Additional arguments to pass to clang when completing.
 Prefix files (-include ...) can be selected with
@@ -201,6 +207,17 @@ Prefix files (-include ...) can be selected with
          prefix
          (company-clang--build-complete-args (- (point) (length prefix)))))
 
+(defun company-clang--prefix ()
+  (let ((symbol (company-grab-symbol)))
+    (if symbol
+        (if (and company-clang-begin-after-member-access
+                 (save-excursion
+                   (forward-char (- (length symbol)))
+                   (looking-back "\\.\\|->" (- (point) 3))))
+            (cons symbol t)
+          symbol)
+      'stop)))
+
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defconst company-clang-required-version 1.1)
@@ -263,7 +280,7 @@ input."
                  buffer-file-name
                  company-clang-executable
                  (not (company-in-string-or-comment))
-                 (or (company-grab-symbol) 'stop)))
+                 (company-clang--prefix)))
     (candidates (company-clang--candidates arg))
     (meta (gethash arg company-clang--meta-cache))
     (crop (and (string-match ":\\|(" arg)
diff --git a/company.el b/company.el
index 2a9b9db..901aac1 100644
--- a/company.el
+++ b/company.el
@@ -280,13 +280,12 @@ Each back-end is a function that takes a variable number 
of arguments.
 The first argument is the command requested from the back-end.  It is one
 of the following:
 
-`prefix': The back-end should return the text to be completed.  It must be
-text immediately before `point'.  Returning nil passes control to the next
-back-end.  The function should return 'stop if it should complete but cannot
-\(e.g. if it is in the middle of a string\).  If the returned value is only
-part of the prefix (e.g. the part after \"->\" in C), the back-end may return a
-cons of prefix and prefix length, which is then used in the
-`company-minimum-prefix-length' test.
+`prefix': The back-end should return the text to be completed.  It must be text
+immediately before `point'.  Returning nil passes control to the next back-end.
+The function should return 'stop if it should complete but cannot \(e.g. if it
+is in the middle of a string\).  Instead of a string, the back-end may return a
+cons where car is the prefix and cdr is used in `company-minimum-prefix-length'
+test. It's either number or t, in which case the test automatically succeeds.
 
 `candidates': The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.
@@ -951,8 +950,9 @@ can retrieve meta-data for them."
 (defun company--good-prefix-p (prefix)
   (and (or (company-explicit-action-p)
            (unless (eq prefix 'stop)
-             (>= (or (cdr-safe prefix) (length prefix))
-                 company-minimum-prefix-length)))
+             (or (eq (cdr-safe prefix) t)
+                 (>= (or (cdr-safe prefix) (length prefix))
+                     company-minimum-prefix-length))))
        (stringp (or (car-safe prefix) prefix))))
 
 (defun company--continue ()

commit 76d189f52b6965447e6b0451fa62181a980fa6fc
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 4 13:21:19 2013 +0400

    company-select-mouse: work correctly when tooltip is expanded up

diff --git a/company.el b/company.el
index 2734ae7..2a9b9db 100644
--- a/company.el
+++ b/company.el
@@ -1338,8 +1338,11 @@ and invoke the normal binding."
            (evt-row (cdr event-col-row)))
       (and (>= evt-col column)
            (< evt-col (+ column width))
-           (> evt-row ovl-row)
-           (<= evt-row (+ ovl-row height) )))))
+           (if (> height 0)
+               (and (> evt-row ovl-row)
+                    (<= evt-row (+ ovl-row height) ))
+             (and (< evt-row ovl-row)
+                  (>= evt-row (+ ovl-row height))))))))
 
 (defun company-select-mouse (event)
   "Select the candidate picked by the mouse."
@@ -1347,12 +1350,16 @@ and invoke the normal binding."
   (let ((event-col-row (posn-actual-col-row (event-start event)))
         (ovl-row (company--row)))
     (if (company--inside-tooltip-p event-col-row ovl-row)
-        (progn
-          (company-set-selection (- (cdr event-col-row)
+        (let ((ovl-height (overlay-get company-pseudo-tooltip-overlay
+                                       'company-height)))
+          (company-set-selection (+ (cdr event-col-row)
                                     (if (zerop company-tooltip-offset)
-                                        1
-                                      (- 2 company-tooltip-offset))
-                                    ovl-row))
+                                        -1
+                                      (- company-tooltip-offset 2))
+                                    (- ovl-row)
+                                    (if (< ovl-height 0)
+                                        (- 1 ovl-height)
+                                      0)))
           t)
       (company-abort)
       (company--unread-last-input)

commit 61e87e829103cc8356807f3dcd77a5bc1f0e09c9
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 4 12:38:10 2013 +0400

    Fix #20

diff --git a/NEWS.md b/NEWS.md
index 92daabb..db8cbe0 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Mouse click outside the tooltip aborts completion.
 * `company-clang` uses standard input to pass the contents of current buffer to
   Clang 2.9+, otherwise saves the buffer and passes the path to the file.
 * `company-clang-auto-save` option has been removed.
diff --git a/company.el b/company.el
index 50205a8..2734ae7 100644
--- a/company.el
+++ b/company.el
@@ -1328,16 +1328,35 @@ and invoke the normal binding."
     (company-abort)
     (company--unread-last-input)))
 
+(defun company--inside-tooltip-p (event-col-row ovl-row)
+  (when company-pseudo-tooltip-overlay
+    (let* ((ovl company-pseudo-tooltip-overlay)
+           (column (overlay-get ovl 'company-column))
+           (width (overlay-get ovl 'company-width))
+           (height (overlay-get ovl 'company-height))
+           (evt-col (car event-col-row))
+           (evt-row (cdr event-col-row)))
+      (and (>= evt-col column)
+           (< evt-col (+ column width))
+           (> evt-row ovl-row)
+           (<= evt-row (+ ovl-row height) )))))
+
 (defun company-select-mouse (event)
   "Select the candidate picked by the mouse."
   (interactive "e")
-  (when (nth 4 (event-start event))
-    (company-set-selection (- (cdr (posn-actual-col-row (event-start event)))
-                              (if (zerop company-tooltip-offset)
-                                  1
-                                (- 2 company-tooltip-offset))
-                              (company--row)))
-    t))
+  (let ((event-col-row (posn-actual-col-row (event-start event)))
+        (ovl-row (company--row)))
+    (if (company--inside-tooltip-p event-col-row ovl-row)
+        (progn
+          (company-set-selection (- (cdr event-col-row)
+                                    (if (zerop company-tooltip-offset)
+                                        1
+                                      (- 2 company-tooltip-offset))
+                                    ovl-row))
+          t)
+      (company-abort)
+      (company--unread-last-input)
+      nil)))
 
 (defun company-complete-mouse (event)
   "Complete the candidate picked by the mouse."
@@ -1769,10 +1788,11 @@ Returns a negative number if the tooltip should be 
displayed above point."
 
         (setq company-pseudo-tooltip-overlay ov)
         (overlay-put ov 'company-replacement-args args)
-        (overlay-put ov 'company-before
-                     (apply 'company--replacement-string
-                            (company--create-lines selection (abs height))
-                            args))
+
+        (let ((lines (company--create-lines selection (abs height))))
+          (overlay-put ov 'company-before
+                       (apply 'company--replacement-string lines args))
+          (overlay-put ov 'company-width (string-width (car lines))))
 
         (overlay-put ov 'company-column column)
         (overlay-put ov 'company-height height)))))
@@ -1784,8 +1804,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
                                    company-selection))))
 
 (defun company-pseudo-tooltip-edit (lines selection)
-  (let ((column (overlay-get company-pseudo-tooltip-overlay 'company-column))
-        (height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
+  (let ((height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (apply 'company--replacement-string
                         (company--create-lines selection (abs height))

commit f5ee458241950b42443415e5bf42eab182b100ce
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 4 10:49:31 2013 +0400

    company-select-mouse: Pick correct item when company-tooltip-offset > 0

diff --git a/company.el b/company.el
index e00ae92..50205a8 100644
--- a/company.el
+++ b/company.el
@@ -1333,8 +1333,10 @@ and invoke the normal binding."
   (interactive "e")
   (when (nth 4 (event-start event))
     (company-set-selection (- (cdr (posn-actual-col-row (event-start event)))
-                              (company--row)
-                              1))
+                              (if (zerop company-tooltip-offset)
+                                  1
+                                (- 2 company-tooltip-offset))
+                              (company--row)))
     t))
 
 (defun company-complete-mouse (event)

commit 0b019b223ccd5cae67211ae8498091f186148477
Author: Constantin <address@hidden>
Date:   Fri Apr 26 23:00:29 2013 +0400

    company-clang: with 2.9+, use stdin
    
    Fall back to saving the buffer in earlier versions automatically.
    Remove the option `company-clang-auto-save'.
    
    Close #18.

diff --git a/NEWS.md b/NEWS.md
index a660d9a..92daabb 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,9 @@
 
 ## Next
 
+* `company-clang` uses standard input to pass the contents of current buffer to
+  Clang 2.9+, otherwise saves the buffer and passes the path to the file.
+* `company-clang-auto-save` option has been removed.
 * Better interaction with `outline-minor-mode`.
 * `company-dabbrev-code` supports all `prog-mode` derivatives.
 
diff --git a/company-clang.el b/company-clang.el
index 954b9be..947afe2 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -38,12 +38,6 @@
   "Location of clang executable."
   :type 'file)
 
-(defcustom company-clang-auto-save t
-  "Determines whether to save the buffer when retrieving completions.
-clang can only complete correctly when the buffer has been saved."
-  :type '(choice (const :tag "Off" nil)
-                 (const :tag "On" t)))
-
 (defcustom company-clang-arguments nil
   "Additional arguments to pass to clang when completing.
 Prefix files (-include ...) can be selected with
@@ -109,6 +103,12 @@ Prefix files (-include ...) can be selected with
 
 (defvar company-clang--meta-cache nil)
 
+(defun company-clang--lang-option ()
+     (if (eq major-mode 'objc-mode)
+         (if (string= "m" (file-name-extension buffer-file-name))
+             "objective-c" "objective-c++")
+       (substring (symbol-name major-mode) 0 -5)))
+
 (defun company-clang--parse-output (prefix objc)
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
@@ -142,7 +142,7 @@ Prefix files (-include ...) can be selected with
          (err (if (re-search-forward pattern nil t)
                   (buffer-substring-no-properties (point-min)
                                                   (1- (match-beginning 0)))
-                ;; Warn the user more agressively if no match was found.
+                ;; Warn the user more aggressively if no match was found.
                 (message "clang failed with error %d:\n%s" res cmd)
                 (buffer-string))))
 
@@ -157,31 +157,41 @@ Prefix files (-include ...) can be selected with
         (goto-char (point-min))))))
 
 (defun company-clang--call-process (prefix &rest args)
-  (let ((objc (derived-mode-p 'objc-mode)))
-    (with-temp-buffer
-      (let ((res (apply 'call-process company-clang-executable nil t nil 
args)))
-        (unless (eq 0 res)
-          (company-clang--handle-error res args))
-        ;; Still try to get any useful input.
-        (company-clang--parse-output prefix objc)))))
+  (let ((objc (derived-mode-p 'objc-mode))
+        (buf (get-buffer-create "*clang-output*"))
+        res)
+    (with-current-buffer buf (erase-buffer))
+    (setq res (if (company-clang--auto-save-p)
+                  (apply 'call-process company-clang-executable nil buf nil 
args)
+                (apply 'call-process-region (point-min) (point-max)
+                       company-clang-executable nil buf nil args)))
+    (with-current-buffer buf
+      (unless (eq 0 res)
+        (company-clang--handle-error res args))
+      ;; Still try to get any useful input.
+      (company-clang--parse-output prefix objc))))
 
 (defsubst company-clang--build-location (pos)
   (save-excursion
     (goto-char pos)
-    (format "%s:%d:%d" buffer-file-name (line-number-at-pos)
+    (format "%s:%d:%d"
+            (if (company-clang--auto-save-p) buffer-file-name "-")
+            (line-number-at-pos)
             (1+ (current-column)))))
 
 (defsubst company-clang--build-complete-args (pos)
   (append '("-cc1" "-fsyntax-only" "-code-completion-macros")
+          (unless (company-clang--auto-save-p)
+            (list "-x" (company-clang--lang-option)))
           company-clang-arguments
           (when (stringp company-clang--prefix)
             (list "-include" (expand-file-name company-clang--prefix)))
           '("-code-completion-at")
           (list (company-clang--build-location pos))
-          (list buffer-file-name)))
+          (list (if (company-clang--auto-save-p) buffer-file-name "-"))))
 
 (defun company-clang--candidates (prefix)
-  (and company-clang-auto-save
+  (and (company-clang--auto-save-p)
        (buffer-modified-p)
        (basic-save-buffer))
   (when (null company-clang--prefix)
@@ -195,6 +205,11 @@ Prefix files (-include ...) can be selected with
 
 (defconst company-clang-required-version 1.1)
 
+(defvar company-clang--version nil)
+
+(defun company-clang--auto-save-p ()
+  (< company-clang--version 2.9))
+
 (defsubst company-clang-version ()
   "Return the version of `company-clang-executable'."
   (with-temp-buffer
@@ -232,15 +247,17 @@ Additional command line arguments can be specified in
 with `company-clang-set-prefix' or automatically through a custom
 `company-clang-prefix-guesser'.
 
-Completions only work correctly when the buffer has been saved.
-`company-clang-auto-save' determines whether to do this automatically."
+With Clang versions before 2.9, we have to save the buffer before performing
+completion.  With Clang 2.9 and later, buffer contents are passed via stardard
+input."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-clang))
     (init (when (memq major-mode company-clang-modes)
             (unless company-clang-executable
               (error "Company found no clang executable"))
-            (when (< (company-clang-version) company-clang-required-version)
+            (setq company-clang--version (company-clang-version))
+            (when (< company-clang--version company-clang-required-version)
               (error "Company requires clang version 1.1"))))
     (prefix (and (memq major-mode company-clang-modes)
                  buffer-file-name

commit 1c8600b4ccc326ea8046e22baff403d7918b14d7
Merge: eda0852 baa85ed
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 3 00:04:33 2013 -0700

    Merge pull request #103 from johan/interpreter-mode-alist
    
    Also aid  "#! /usr/bin/env node" type auto major mode selection


commit baa85ed19e057e78d24f001f9331d31575c8c688
Author: Johan Sundström <address@hidden>
Date:   Thu May 2 23:59:27 2013 -0700

    Also aid "#! /usr/bin/env node" type auto major mode selection

diff --git a/js2-mode.el b/js2-mode.el
index afd1981..b489458 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -56,6 +56,10 @@
 
 ;;   (add-hook 'js-mode-hook 'js2-minor-mode)
 
+;; You may also want to hook it in for shell scripts running via node.js:
+
+;;   (add-to-list 'interpreter-mode-alist '("node" . js2-mode))
+
 ;; To customize how it works:
 ;;   M-x customize-group RET js2-mode RET
 

commit eda08529b0f8cecb84c57ced2e0776524c830a8b
Merge: 5c3f8ac 073e167
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 30 21:47:28 2013 -0700

    Merge pull request #101 from pd/node-typed-arrays
    
    Add typed array externs


commit 073e167270d6a968fef45c1f0d20aeedc062fa52
Author: Kyle Hargraves <address@hidden>
Date:   Tue Apr 30 20:37:59 2013 -0700

    Add js2-typed-array-externs, js2-set-default-externs

diff --git a/js2-mode.el b/js2-mode.el
index 7ac3105..afd1981 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -167,11 +167,6 @@
             ;; W3C XML
             XPathResult XMLHttpRequest
 
-            ;; Khronos Typed Array Specification
-            ArrayBuffer Uint8ClampedArray DataView
-            Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
-            Float32Array Float64Array
-
             ;; console object.  Provided by at least Chrome and Firefox.
             console))
   "Browser externs.
@@ -191,14 +186,18 @@ Set `js2-include-rhino-externs' to t to include them.")
 (defvar js2-node-externs
   (mapcar 'symbol-name
           '(__dirname __filename Buffer clearInterval clearTimeout require
-            console exports global module process setInterval setTimeout
+            console exports global module process setInterval setTimeout))
+  "Node.js externs.
+Set `js2-include-node-externs' to t to include them.")
 
-            ;; node.js also supports Typed Arrays
-            ArrayBuffer Uint8ClampedArray DataView
+(defvar js2-typed-array-externs
+  (mapcar 'symbol-name
+          '(ArrayBuffer Uint8ClampedArray DataView
             Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
             Float32Array Float64Array))
-  "Node.js externs.
-Set `js2-include-node-externs' to t to include them.")
+  "Khronos typed array externs. Available in most modern browsers and
+in node.js >= 0.6. If `js2-include-node-externs' or 
`js2-include-browser-externs'
+are enabled, these will also be included.")
 
 ;;; Variables
 
@@ -6415,6 +6414,17 @@ it is considered declared."
                               'js2-external-variable))))
     (setq js2-recorded-identifiers nil)))
 
+(defun js2-set-default-externs ()
+  "Set the value of `js2-default-externs' based on the various
+`js2-include-?-externs' variables."
+  (setq js2-default-externs
+        (append js2-ecma-262-externs
+                (if js2-include-browser-externs js2-browser-externs)
+                (if js2-include-rhino-externs js2-rhino-externs)
+                (if js2-include-node-externs js2-node-externs)
+                (if (or js2-include-browser-externs js2-include-node-externs)
+                    js2-typed-array-externs))))
+
 ;;; IMenu support
 
 ;; We currently only support imenu, but eventually should support speedbar and
@@ -10055,11 +10065,7 @@ highlighting features of `js2-mode'."
   (set (make-local-variable 'max-lisp-eval-depth)
        (max max-lisp-eval-depth 3000))
   (setq next-error-function #'js2-next-error)
-  (setq js2-default-externs
-        (append js2-ecma-262-externs
-                (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)
-                (if js2-include-node-externs js2-node-externs)))
+  (js2-set-default-externs)
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
       (setq js2-idle-timer-delay
@@ -10240,12 +10246,6 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
     (make-local-variable 'adaptive-fill-regexp)
     (c-setup-paragraph-variables))
 
-  (setq js2-default-externs
-        (append js2-ecma-262-externs
-                (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)
-                (if js2-include-node-externs js2-node-externs)))
-
   (setq font-lock-defaults '(nil t))
 
   ;; Experiment:  make reparse-delay longer for longer files.
@@ -10267,6 +10267,7 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
         js2-mode-comments-hidden nil
         js2-mode-buffer-dirty-p t
         js2-mode-parsing nil)
+  (js2-set-default-externs)
   (js2-reparse))
 
 (defun js2-mode-exit ()

commit ed098081e740a9db75af3ea8f77edc3191de3d58
Author: Kyle Hargraves <address@hidden>
Date:   Tue Apr 30 14:33:28 2013 -0700

    Add typed array types to js2-node-externs
    
    node.js has supported typed arrays since 0.6:
    
    https://github.com/joyent/node/wiki/API-changes-between-v0.4-and-v0.6
    https://github.com/joyent/node/issues/1322
    https://github.com/joyent/node/commit/97b0000

diff --git a/js2-mode.el b/js2-mode.el
index 06824bd..7ac3105 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -191,7 +191,12 @@ Set `js2-include-rhino-externs' to t to include them.")
 (defvar js2-node-externs
   (mapcar 'symbol-name
           '(__dirname __filename Buffer clearInterval clearTimeout require
-            console exports global module process setInterval setTimeout))
+            console exports global module process setInterval setTimeout
+
+            ;; node.js also supports Typed Arrays
+            ArrayBuffer Uint8ClampedArray DataView
+            Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
+            Float32Array Float64Array))
   "Node.js externs.
 Set `js2-include-node-externs' to t to include them.")
 

commit 947aebba714790a8d5be48987f32af1a1def2bbe
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 26 12:41:02 2013 +0400

    * company-buffer-lines: Get rid of `done'
    
    When there's no trailing newline, `vertical-motion' moves to eol anyway.
    So it's all fine, as long as END <= (point-max).

diff --git a/company.el b/company.el
index 4b5dbcc..e00ae92 100644
--- a/company.el
+++ b/company.el
@@ -1621,15 +1621,14 @@ Example:
 
 (defun company-buffer-lines (beg end)
   (goto-char beg)
-  (let (lines done)
-    (while (and (< (point) end) (not done))
+  (let (lines)
+    (while (< (point) end)
       (let ((bol (point)))
         ;; A visual line can contain several physical lines (e.g. with 
outline's
         ;; folding overlay).  Take only the first one.
         (re-search-forward "$")
         (push (buffer-substring bol (min end (point))) lines))
-      (unless (= 1 (vertical-motion 1))
-        (setq done t)))
+      (vertical-motion 1))
     (nreverse lines)))
 
 (defsubst company-modify-line (old new offset)

commit a696ca3aef5df9260ee2564b0c0b77d5b5c3a8a5
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 26 12:25:48 2013 +0400

    Fix #16

diff --git a/NEWS.md b/NEWS.md
index 31c50b4..a660d9a 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Better interaction with `outline-minor-mode`.
 * `company-dabbrev-code` supports all `prog-mode` derivatives.
 
 ## 2013-04-16 (0.6.8)
diff --git a/company.el b/company.el
index 7f30932..4b5dbcc 100644
--- a/company.el
+++ b/company.el
@@ -1621,13 +1621,15 @@ Example:
 
 (defun company-buffer-lines (beg end)
   (goto-char beg)
-  (let (lines)
-    (while (and (= 1 (vertical-motion 1))
-                (<= (point) end))
-      (push (buffer-substring beg (min end (1- (point)))) lines)
-      (setq beg (point)))
-    (unless (eq beg end)
-      (push (buffer-substring beg end) lines))
+  (let (lines done)
+    (while (and (< (point) end) (not done))
+      (let ((bol (point)))
+        ;; A visual line can contain several physical lines (e.g. with 
outline's
+        ;; folding overlay).  Take only the first one.
+        (re-search-forward "$")
+        (push (buffer-substring bol (min end (point))) lines))
+      (unless (= 1 (vertical-motion 1))
+        (setq done t)))
     (nreverse lines)))
 
 (defsubst company-modify-line (old new offset)
@@ -1802,6 +1804,8 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defun company-pseudo-tooltip-unhide ()
   (when company-pseudo-tooltip-overlay
     (overlay-put company-pseudo-tooltip-overlay 'invisible t)
+    ;; Beat outline's folding overlays, at least.
+    (overlay-put company-pseudo-tooltip-overlay 'priority 1)
     (overlay-put company-pseudo-tooltip-overlay 'before-string
                  (overlay-get company-pseudo-tooltip-overlay 'company-before))
     (overlay-put company-pseudo-tooltip-overlay 'window (selected-window))))

commit 0fd01279dff979f8831764d96dd7d9a1f046bf29
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 26 09:31:04 2013 +0400

    * company-dabbrev-code-modes: Remove espresso-mode, add prog-mode

diff --git a/NEWS.md b/NEWS.md
index 8718d4b..31c50b4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,9 @@
 # History of user-visible changes
 
+## Next
+
+* `company-dabbrev-code` supports all `prog-mode` derivatives.
+
 ## 2013-04-16 (0.6.8)
 
 * `company-auto-complete` is disabled by default.
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 2b13237..e4c548e 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -35,10 +35,9 @@
 
 (defcustom company-dabbrev-code-modes
   '(asm-mode batch-file-mode c++-mode c-mode cperl-mode csharp-mode css-mode
-    emacs-lisp-mode erlang-mode espresso-mode f90-mode fortran-mode
-    haskell-mode java-mode javascript-mode jde-mode js2-mode lisp-mode
-    lua-mode objc-mode perl-mode php-mode python-mode ruby-mode scheme-mode
-    shell-script-mode)
+    emacs-lisp-mode erlang-mode f90-mode fortran-mode haskell-mode java-mode
+    javascript-mode jde-mode js2-mode lisp-mode lua-mode objc-mode perl-mode
+    php-mode prog-mode python-mode ruby-mode scheme-mode shell-script-mode)
   "Modes that use `company-dabbrev-code'.
 In all these modes `company-dabbrev-code' will complete only symbols, not text
 in comments or strings.  In other modes `company-dabbrev-code' will pass 
control

commit 1d919104f29f8a5dd9f9f5e09b6c4d168a43e3b5
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Apr 21 07:57:29 2013 +0200

    * eldoc-eval.el (eldoc-mode-in-minibuffer): Get rid of 
`minibuffer-completion-contents'.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index b5e377f..2879caf 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -72,13 +72,6 @@ Should take one arg: the string to display"
          (not cursor-in-echo-area)
          (not (eq (selected-window) (minibuffer-window))))))
 
-;; Emacs-24.4 make `minibuffer-completion-contents' obsolete,
-;; inline it to shutup byte compiler.
-(defun eldoc-eval-minibuffer-completion-contents ()
-  "Return the user input in a minibuffer before point as a string.
-That is what completion commands operate on."
-  (buffer-substring (field-beginning) (point)))
-
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil
   "Store actives minibuffers with eldoc enabled.")
@@ -159,14 +152,10 @@ See `with-eldoc-in-minibuffer'."
     (condition-case err
         (when (member buf eldoc-active-minibuffers-list)
           (with-current-buffer buf
-            (let* ((str-all (eldoc-eval-minibuffer-completion-contents))
-                   (sym     (when str-all
-                              (with-temp-buffer
-                                (insert str-all)
-                                (goto-char (point-max))
-                                (unless (looking-back ")\\|\"")
-                                  (forward-char -1))
-                                (eldoc-current-symbol))))
+            (let* ((sym (save-excursion
+                          (unless (looking-back ")\\|\"")
+                            (forward-char -1))
+                          (eldoc-current-symbol)))
                    (info-fn (eldoc-fnsym-in-current-sexp))
                    (doc     (or (eldoc-get-var-docstring sym)
                                 (eldoc-get-fnsym-args-string

commit 4c4829d664ab875f7cd63061b22b68d58846e19d
Author: Leo Liu <address@hidden>
Date:   Sat Apr 20 20:22:26 2013 +0800

    Doc fix and support the silver search

diff --git a/README.rst b/README.rst
index 36c5fac..9d4e14f 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,12 @@
-=======================================================
- Emacs Interface to `Ack <http://betterthangrep.com>`_
-=======================================================
+==============================================================
+ Emacs Interface to `Ack <http://beyondgrep.com>`_-like Tools
+==============================================================
  
-This package brings the full power of `ack
-<http://betterthangrep.com>`_ to `emacs
-<http://www.gnu.org/software/emacs>`_ by allowing you to run it
-seamlessly with its large set of options.
+This package brings the full power of `ack <http://beyondgrep.com>`_
+to `emacs <http://www.gnu.org/software/emacs>`_ by allowing you to run
+it seamlessly with its large set of options. Ack-like tools such as
+`the silver searcher <https://github.com/ggreer/the_silver_searcher>`_
+and ``git/hg/bzr grep`` are well supported too.
 
 It is part of `GNU ELPA <http://elpa.gnu.org>`_ - the official package
 archive for `emacs <http://www.gnu.org/software/emacs>`_. Patches,
@@ -14,9 +15,11 @@ feature requests and bug reports are welcome.
 Features
 --------
 
-- Keep all features of `ack <http://betterthangrep.com>`_ and more
+- Keep all features of `ack <http://beyondgrep.com>`_ and more
 - Handle colors using the standard library ``ansi-color.el``
 - Completion for ack options while reading from the minibuffer
+- Support `the silver search (ag)
+  <https://github.com/ggreer/the_silver_searcher>`_
 - Support ``git grep``, ``hg grep`` and ``bzr grep``
 
 Install
diff --git a/ack.el b/ack.el
index f7d8fa2..01529d7 100644
--- a/ack.el
+++ b/ack.el
@@ -1,9 +1,9 @@
-;;; ack.el --- interface to ack            -*- lexical-binding: t; -*-
+;;; ack.el --- interface to ack-like tools   -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 1.0
+;; Version: 1.01
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
 ;; URL: https://github.com/leoliu/ack-el
@@ -23,11 +23,14 @@
 
 ;;; Commentary:
 
-;; This package provides an interface to ack http://betterthangrep.com
-;; -- a tool like grep, designed for programmers with large trees of
+;; This package provides an interface to ack http://beyondgrep.com --
+;; a tool like grep, designed for programmers with large trees of
 ;; heterogeneous source code. It builds on standard packages
-;; `compile.el' and `ansi-color.el' and let you seamlessly run `ack'
+;; `compile.el' and `ansi-color.el' and lets you seamlessly run `ack'
 ;; with its large set of options.
+;;
+;; Ack-like tools such as the silver search (ag) and git/hg/bzr grep
+;; are well supported too.
 
 ;;; Usage:
 
@@ -75,13 +78,15 @@
   ;; Note: on GNU/Linux ack may be renamed to ack-grep
   (concat (file-name-nondirectory (or (executable-find "ack-grep")
                                       (executable-find "ack")
+                                      (executable-find "ag")
                                       "ack")) " ")
-  "The default ack command for \\[ack].
+  "The default command for \\[ack].
 
 Note also options to ack can be specified in ACK_OPTIONS
-environment variable and ~/.ackrc, which you can disable by the
+environment variable and .ackrc, which you can disable by the
 --noenv switch."
   :type 'string
+  :safe 'stringp
   :group 'ack)
 
 (defcustom ack-buffer-name-function nil
@@ -260,7 +265,9 @@ This gets tacked on the end of the generated expressions.")
   (interactive)
   (delete-minibuffer-contents)
   (let ((ack (or (car (split-string ack-command nil t)) "ack")))
-    (skeleton-insert `(nil ,ack " -g '(?i:" _ ")'"))))
+    (if (equal ack "ag")
+        (skeleton-insert `(nil ,ack " -ig '" _ "'"))
+      (skeleton-insert `(nil ,ack " -g '(?i:" _ ")'")))))
 
 ;; Work around bug http://debbugs.gnu.org/13811
 (defvar ack--project-root nil)          ; dynamically bound in `ack'
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index 3584e83..3029367 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -23,7 +23,7 @@
 ;;; Commentary:
 
 ;; Provide pcompletion support for the cli tool `ack' which can be
-;; downloaded from http://betterthangrep.com.
+;; downloaded from http://beyondgrep.com.
 ;;
 ;; Install:
 ;;   (autoload 'pcomplete/ack "pcmpl-ack")

commit 0a642d5d31a8e0e22a4b2b2a48dafd6393b81aa9
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Apr 20 09:39:08 2013 +0200

    * eldoc-eval.el (eldoc-eval-minibuffer-completion-contents): like 
`minibuffer-completion-contents' to shutup byte compiler.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index 419ae5a..b5e377f 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -72,6 +72,13 @@ Should take one arg: the string to display"
          (not cursor-in-echo-area)
          (not (eq (selected-window) (minibuffer-window))))))
 
+;; Emacs-24.4 make `minibuffer-completion-contents' obsolete,
+;; inline it to shutup byte compiler.
+(defun eldoc-eval-minibuffer-completion-contents ()
+  "Return the user input in a minibuffer before point as a string.
+That is what completion commands operate on."
+  (buffer-substring (field-beginning) (point)))
+
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil
   "Store actives minibuffers with eldoc enabled.")
@@ -152,7 +159,7 @@ See `with-eldoc-in-minibuffer'."
     (condition-case err
         (when (member buf eldoc-active-minibuffers-list)
           (with-current-buffer buf
-            (let* ((str-all (minibuffer-completion-contents))
+            (let* ((str-all (eldoc-eval-minibuffer-completion-contents))
                    (sym     (when str-all
                               (with-temp-buffer
                                 (insert str-all)

commit 6f34d76541a64d51ae40ef0f5864072c7e677511
Merge: ffdfdad 8563865
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Apr 20 09:15:48 2013 +0200

    Merge branch 'master' of github.com:thierryvolpiatto/eldoc-eval


commit ffdfdad41eb066a3e967efb25f05e4cb776a20bf
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Apr 20 09:14:33 2013 +0200

    * eldoc-eval.el (eval-prefered-function): Renamed with eldoc prefix.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index dbc142e..87870c0 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -45,7 +45,7 @@ Should take one arg: the string to display"
   :group 'eldoc
   :type 'number)
 
-(defcustom eval-prefered-function 'pp-eval-expression
+(defcustom eldoc-eval-prefered-function 'pp-eval-expression
   "Prefered function to use with `M-:'."
   :group 'lisp
   :type 'function)
@@ -173,7 +173,7 @@ See `with-eldoc-in-minibuffer'."
   "Eval expression with eldoc support in mode-line."
   (interactive)
   (with-eldoc-in-minibuffer
-    (call-interactively eval-prefered-function)))
+    (call-interactively eldoc-eval-prefered-function)))
 
 ;; Bind it to `M-:'.
 (global-set-key [remap eval-expression] 'eval-expression-with-eldoc)

commit 7c61476f696330e560d5d868fe8f779cd36b113c
Author: Leo Liu <address@hidden>
Date:   Sat Apr 20 11:36:07 2013 +0800

    Doc fix and release 1.0

diff --git a/README.rst b/README.rst
index f6910f9..36c5fac 100644
--- a/README.rst
+++ b/README.rst
@@ -1,75 +1,43 @@
-==========================================
- Emacs Interface to command-line tool ack
-==========================================
-
-From http://betterthangrep.com/
-
-    ack is a tool like grep, designed for programmers with large trees
-    of heterogeneous source code.
-
-    ack is written purely in Perl, and takes advantage of the power of
-    Perl's regular expressions.
-
-This package is part of `GNU ELPA <http://elpa.gnu.org>`_.
-
-Patches, feature requests and bug reports are welcome. Thanks.
+=======================================================
+ Emacs Interface to `Ack <http://betterthangrep.com>`_
+=======================================================
+ 
+This package brings the full power of `ack
+<http://betterthangrep.com>`_ to `emacs
+<http://www.gnu.org/software/emacs>`_ by allowing you to run it
+seamlessly with its large set of options.
+
+It is part of `GNU ELPA <http://elpa.gnu.org>`_ - the official package
+archive for `emacs <http://www.gnu.org/software/emacs>`_. Patches,
+feature requests and bug reports are welcome.
 
 Features
 --------
 
-- Neither ``--nogroup`` nor ``--noheading`` is required
+- Keep all features of `ack <http://betterthangrep.com>`_ and more
 - Handle colors using the standard library ``ansi-color.el``
 - Completion for ack options while reading from the minibuffer
 - Support ``git grep``, ``hg grep`` and ``bzr grep``
 
-Screenshots
------------
-
-.. figure:: http://i.imgur.com/mrk8k.png
-   :width: 400 px
-   :target: http://i.imgur.com/mrk8k.png
-   :alt: ack-git-grep.png
-
-   ``git --no-pager grep -n --color 'hg grep'``
-
-.. figure:: http://i.imgur.com/a72Ap.png
-   :width: 400 px
-   :target: http://i.imgur.com/a72Ap.png
-   :alt: ack-emacs23-1.png
-
-   ``ack --column 'ack is.*tool'``
-
-.. figure:: http://i.imgur.com/U2vFz.png
-   :width: 400 px
-   :target: http://i.imgur.com/U2vFz.png
-   :alt: ack-emacs23-2.png
-
-   ``ack --column --nogroup --nocolor 'ack is.*tool'``
-
 Install
 -------
 
-Place ``ack.el`` in the ``load-path`` and add to your init file::
-
-  (require 'ack)
+``M-x package-install RET ack RET``
 
-or::
-
- (autoload 'ack "ack" nil t)
-
-Completion (optional)
-~~~~~~~~~~~~~~~~~~~~~
+Screenshots
+-----------
 
-UPDATE: ``pcmpl-ack.el`` is merged into emacs trunk and should appear
-in emacs 24.4.
+* ack
 
-Place ``pcmpl-ack.el`` in the ``load-path`` and add::
+.. figure:: http://i.imgur.com/VwWyzAe.png
+   :target: http://i.imgur.com/VwWyzAe.png
+   :alt: ack.png
 
-  (autoload 'pcomplete/ack "pcmpl-ack")
-  (autoload 'pcomplete/ack-grep "pcmpl-ack")
+* git grep
 
-to your init file. After this you will be able complete ``ack``
-options while ``M-x ack`` or in shell/eshell.
+.. figure:: http://i.imgur.com/rwjC4pa.png
+   :target: http://i.imgur.com/rwjC4pa.png
+   :alt: ack-git-grep.png
 
 Usage
 -----
diff --git a/ack.el b/ack.el
index 12b8815..f7d8fa2 100644
--- a/ack.el
+++ b/ack.el
@@ -1,9 +1,9 @@
-;;; ack.el --- Emacs interface to ack           -*- lexical-binding: t; -*-
+;;; ack.el --- interface to ack            -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.9
+;; Version: 1.0
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
 ;; URL: https://github.com/leoliu/ack-el
@@ -23,8 +23,31 @@
 
 ;;; Commentary:
 
-;; ack is a tool like grep, designed for programmers with large trees
-;; of heterogeneous source code - http://betterthangrep.com/.
+;; This package provides an interface to ack http://betterthangrep.com
+;; -- a tool like grep, designed for programmers with large trees of
+;; heterogeneous source code. It builds on standard packages
+;; `compile.el' and `ansi-color.el' and let you seamlessly run `ack'
+;; with its large set of options.
+
+;;; Usage:
+
+;; +  Type `M-x ack' and provide a pattern to search.
+;; +  Type `C-u M-x ack' to search from current project root.
+;; +  Type `C-u C-u M-x ack' to interactively choose a directory to
+;;    search.
+;;
+;; Note: use `ack-default-directory-function' for customised
+;; behaviour.
+;;
+;; When in the minibuffer the following key bindings may be useful:
+;;
+;; +  `M-I' inserts a template for case-insensitive file name search
+;; +  `M-G' inserts a template for `git grep', `hg grep' or `bzr grep'
+;; +  `M-Y' inserts the symbol at point from the window before entering
+;;    the minibuffer
+;; +  `TAB' completes ack options
+
+;;; Bugs: https://github.com/leoliu/ack-el/issues
 
 ;;; Code:
 
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index 942a552..3584e83 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -1,6 +1,6 @@
-;;; pcmpl-ack.el --- completion for ack tool    -*- lexical-binding: t; -*-
+;;; pcmpl-ack.el --- completion for ack    -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 2012-2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience

commit 152bc897170749a4fb24ab0f0a0d32dd5523e4f9
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 19 05:03:44 2013 +0400

    Track with githalytics

diff --git a/README.md b/README.md
index db5f6b6..5501ec2 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 See the [homepage](http://company-mode.github.com/).
+[![githalytics.com 
alpha](https://cruel-carlota.pagodabox.com/336ef4be2595a7859d52e2c17b7da2b2 
"githalytics.com")](http://githalytics.com/company-mode/company-mode)

commit 92ac3d0ef663bca26abbda33cc20a02a58b1c328
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 16 15:36:19 2013 +0400

    Release 0.6.8

diff --git a/NEWS.md b/NEWS.md
index 91064a4..8718d4b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,6 @@
 # History of user-visible changes
 
-## Next
+## 2013-04-16 (0.6.8)
 
 * `company-auto-complete` is disabled by default.
 * `company-auto-complete-chars` default value includes fewer syntax classes.
@@ -9,7 +9,7 @@
 * `company-clang` expands function calls for all three modes now.
 * `company-clang` supports `c++-mode` by default.
 
-## 2013-04-01 (0.6.7)
+## 2013-04-05 (0.6.7)
 
 * Two `company-elisp` tweaks.
 
diff --git a/company.el b/company.el
index 9f13518..7f30932 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.7
+;; Version: 0.6.8
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit 40752cef83b8b7fbc8d662bd4fcf532b2250b2aa
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 16 15:31:20 2013 +0400

    Revert "company--multi-backend-adapter: Use each respective backend's 
prefix"
    
    This reverts commit a982f0fe043c31aca1a11a663c41c33b76ef0c19.
    
    Maybe re-apply later; will have to save the correspondence between 
candidates
    and backends, e.g. for company-strip-prefix.

diff --git a/NEWS.md b/NEWS.md
index b63d5ed..91064a4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,9 +2,6 @@
 
 ## Next
 
-* Candidates from grouped back-ends are retrieved more accurately: each
-  `candidates` command receives in the second argument the respective value the
-  back-end returned to the `prefix` command.
 * `company-auto-complete` is disabled by default.
 * `company-auto-complete-chars` default value includes fewer syntax classes.
 * In expanded function calls, arguments skipped by the user default to "argN".
diff --git a/company-tests.el b/company-tests.el
index 657486b..309d8f1 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -159,25 +159,6 @@
       (should (null company-candidates))
       (should (null (company-explicit-action-p))))))
 
-(ert-deftest company-multi-backend-adapter-uses-respective-prefixes ()
-  ;; And ignores the second argument.
-  (let ((company-backend
-         (list (lambda (command &optional arg)
-                 (case command
-                   (prefix "bar")
-                   (candidates (mapcar (lambda (tail) (concat arg "-" tail))
-                                       '("a" "b" "c")))))
-               (lambda (command &optional arg)
-                 (case command
-                   (prefix "foo-bar")
-                   (candidates (mapcar (lambda (tail) (concat arg "-" tail))
-                                       '("d" "e"))))))))
-    (should (equal (sort '("bar-a" "bar-b" "bar-c" "foo-bar-d" "foo-bar-e")
-                         'string<)
-                   (company-call-backend 'candidates "hubba-hubba")))))
-
-;; Pseudo-Tooltip
-
 (ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
   (with-temp-buffer
     (save-window-excursion
diff --git a/company.el b/company.el
index 3fa8353..9f13518 100644
--- a/company.el
+++ b/company.el
@@ -658,9 +658,9 @@ keymap during active completions (`company-active-map'):
     (case command
       (candidates
        (loop for backend in backends
-             for prefix = (funcall backend 'prefix)
-             when prefix
-             append (funcall backend 'candidates prefix)))
+             when (equal (funcall backend 'prefix)
+                         (car args))
+             append (apply backend 'candidates args)))
       (sorted nil)
       (duplicates t)
       (otherwise

commit caa962bb9d4ce1760170fd3da1d4cdf653060204
Author: Leo Liu <address@hidden>
Date:   Tue Apr 16 14:31:33 2013 +0800

    Notice: pcmpl-ack.el merged into emacs trunk

diff --git a/README.rst b/README.rst
index df1e75a..f6910f9 100644
--- a/README.rst
+++ b/README.rst
@@ -60,6 +60,9 @@ or::
 Completion (optional)
 ~~~~~~~~~~~~~~~~~~~~~
 
+UPDATE: ``pcmpl-ack.el`` is merged into emacs trunk and should appear
+in emacs 24.4.
+
 Place ``pcmpl-ack.el`` in the ``load-path`` and add::
 
   (autoload 'pcomplete/ack "pcmpl-ack")

commit a982f0fe043c31aca1a11a663c41c33b76ef0c19
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 16 06:24:53 2013 +0400

    company--multi-backend-adapter: Use each respective backend's prefix

diff --git a/NEWS.md b/NEWS.md
index 91064a4..b63d5ed 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,9 @@
 
 ## Next
 
+* Candidates from grouped back-ends are retrieved more accurately: each
+  `candidates` command receives in the second argument the respective value the
+  back-end returned to the `prefix` command.
 * `company-auto-complete` is disabled by default.
 * `company-auto-complete-chars` default value includes fewer syntax classes.
 * In expanded function calls, arguments skipped by the user default to "argN".
diff --git a/company-tests.el b/company-tests.el
index 309d8f1..657486b 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -159,6 +159,25 @@
       (should (null company-candidates))
       (should (null (company-explicit-action-p))))))
 
+(ert-deftest company-multi-backend-adapter-uses-respective-prefixes ()
+  ;; And ignores the second argument.
+  (let ((company-backend
+         (list (lambda (command &optional arg)
+                 (case command
+                   (prefix "bar")
+                   (candidates (mapcar (lambda (tail) (concat arg "-" tail))
+                                       '("a" "b" "c")))))
+               (lambda (command &optional arg)
+                 (case command
+                   (prefix "foo-bar")
+                   (candidates (mapcar (lambda (tail) (concat arg "-" tail))
+                                       '("d" "e"))))))))
+    (should (equal (sort '("bar-a" "bar-b" "bar-c" "foo-bar-d" "foo-bar-e")
+                         'string<)
+                   (company-call-backend 'candidates "hubba-hubba")))))
+
+;; Pseudo-Tooltip
+
 (ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
   (with-temp-buffer
     (save-window-excursion
diff --git a/company.el b/company.el
index 9f13518..3fa8353 100644
--- a/company.el
+++ b/company.el
@@ -658,9 +658,9 @@ keymap during active completions (`company-active-map'):
     (case command
       (candidates
        (loop for backend in backends
-             when (equal (funcall backend 'prefix)
-                         (car args))
-             append (apply backend 'candidates args)))
+             for prefix = (funcall backend 'prefix)
+             when prefix
+             append (funcall backend 'candidates prefix)))
       (sorted nil)
       (duplicates t)
       (otherwise

commit b7f831babd449ba7ed04f1e3a7e82ff178af2c18
Author: Dmitry Gutov <address@hidden>
Date:   Sun Apr 14 06:45:59 2013 +0400

    company-template-c-like-templatify: use "argN" as actual field text
    
    * company-template-add-field: Change the third argument type back; add an
      optional fourth argument; move point to the end of the field.
    
    * company-template-c-like-templatify, company-clang-objc-templatify: Adjust 
for
      the above. Use `point-marker'.
    
    * company-template-field-at: Extract from `company-template-forward-field'.

diff --git a/NEWS.md b/NEWS.md
index cec4fa2..91064a4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,8 +4,9 @@
 
 * `company-auto-complete` is disabled by default.
 * `company-auto-complete-chars` default value includes fewer syntax classes.
+* In expanded function calls, arguments skipped by the user default to "argN".
 * `company-eclim` and `company-clang` do not strip argument types from fields.
-* `company-clang` expand function calls into templates for all three modes now.
+* `company-clang` expands function calls for all three modes now.
 * `company-clang` supports `c++-mode` by default.
 
 ## 2013-04-01 (0.6.7)
diff --git a/company-clang.el b/company-clang.el
index 60e29c1..954b9be 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -208,22 +208,18 @@ Prefix files (-include ...) can be selected with
       0)))
 
 (defun company-clang-objc-templatify (selector)
-  (let* ((end (point))
+  (let* ((end (point-marker))
          (beg (- (point) (length selector)))
          (templ (company-template-declare-template beg end))
          (cnt 0))
     (save-excursion
       (goto-char beg)
-      (while (search-forward ":" end t)
-        (let* ((name (format "arg%d" cnt))
-               (len (length name)))
-          (incf end len)
-          (let ((pt (point)))
-            (insert name)
-            (company-template-add-field templ pt (point)))
-          (when (< (point) end)
-            (insert " ")
-            (incf end))
+      (catch 'stop
+        (while (search-forward ":" end t)
+          (company-template-add-field templ (point) (format "arg%d" cnt))
+          (if (< (point) end)
+              (insert " ")
+            (throw 'stop t))
           (incf cnt))))
     (company-template-move-to-first templ)))
 
diff --git a/company-template.el b/company-template.el
index fd4447f..6ffd648 100644
--- a/company-template.el
+++ b/company-template.el
@@ -64,10 +64,12 @@
            (setq minimum pos)))
     (push-mark)
     (goto-char minimum)
-    (let ((field (loop for ovl in (overlays-at start)
-                       when (overlay-get ovl 'company-template-parent)
-                       return ovl)))
-      (company-template-remove-field field))))
+    (company-template-remove-field (company-template-field-at start))))
+
+(defun company-template-field-at (&optional point)
+  (loop for ovl in (overlays-at (or point (point)))
+        when (overlay-get ovl 'company-template-parent)
+        return ovl))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -91,21 +93,26 @@
         (delq templ company-template--buffer-templates))
   (delete-overlay templ))
 
-(defun company-template-add-field (templ beg end)
-  "Add a field to template TEMPL, from BEG to END."
+(defun company-template-add-field (templ pos text &optional display)
+  "Add new field to template TEMPL at POS, inserting TEXT.
+When DISPLAY is non-nil, set the respective property on the overlay.
+Leave point at the end of the field."
   (assert templ)
-  (save-excursion
-    (when (> end (overlay-end templ))
-      (move-overlay templ (overlay-start templ) end))
-    (let ((ov (make-overlay beg end))
-          (siblings (overlay-get templ 'company-template-fields)))
-      ;; (overlay-put ov 'evaporate t)
-      (overlay-put ov 'intangible t)
-      (overlay-put ov 'face 'company-template-field)
-      (overlay-put ov 'company-template-parent templ)
-      (overlay-put ov 'insert-in-front-hooks '(company-template-insert-hook))
-      (push ov siblings)
-      (overlay-put templ 'company-template-fields siblings))))
+  (goto-char pos)
+  (insert text)
+  (when (> (point) (overlay-end templ))
+    (move-overlay templ (overlay-start templ) (point)))
+  (let ((ov (make-overlay pos (+ pos (length text))))
+        (siblings (overlay-get templ 'company-template-fields)))
+    ;; (overlay-put ov 'evaporate t)
+    (overlay-put ov 'intangible t)
+    (overlay-put ov 'face 'company-template-field)
+    (when display
+      (overlay-put ov 'display display))
+    (overlay-put ov 'company-template-parent templ)
+    (overlay-put ov 'insert-in-front-hooks '(company-template-insert-hook))
+    (push ov siblings)
+    (overlay-put templ 'company-template-fields siblings)))
 
 (defun company-template-remove-field (ovl &optional clear)
   (when (overlayp ovl)
@@ -140,17 +147,21 @@
 ;; common 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun company-template-c-like-templatify (call)
-  (let* ((end (point))
-         (beg (- (point) (length call))))
+  (let* ((end (point-marker))
+         (beg (- (point) (length call)))
+         (cnt 0))
     (goto-char beg)
     (when (search-forward "(" end 'move)
       (if (eq (char-after) ?\))
           (forward-char 1)
         (let ((templ (company-template-declare-template beg end)))
           (while (re-search-forward (concat " *\\([^,)]*\\)[,)]") end t)
-            (company-template-add-field templ
-                                        (match-beginning 1)
-                                        (match-end 1)))
+            (let ((sig (match-string 1)))
+              (delete-region (match-beginning 1) (match-end 1))
+              (save-excursion
+                (company-template-add-field templ (match-beginning 1)
+                                            (format "arg%d" cnt) sig))
+              (incf cnt)))
           (company-template-move-to-first templ))))))
 
 (provide 'company-template)
diff --git a/company-tests.el b/company-tests.el
index 5aa4fd8..309d8f1 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -29,6 +29,8 @@
 (require 'company)
 (require 'company-keywords)
 
+;;; Core
+
 (ert-deftest company-sorted-keywords ()
   "Test that keywords in `company-keywords-alist' are in alphabetical order."
   (dolist (pair company-keywords-alist)
@@ -173,15 +175,17 @@
         (company-call 'open-line 1)
         (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
 
+;;; Template
+
 (ert-deftest company-template-removed-after-the-last-jump ()
   (with-temp-buffer
-    (insert "{ foo foo }")
+    (insert "{ }")
     (goto-char 2)
     (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
       (save-excursion
         (dotimes (i 2)
-          (search-forward "foo")
-          (company-template-add-field tpl (match-beginning 0) (match-end 0))))
+          (insert " ")
+          (company-template-add-field tpl (point) "foo")))
       (company-call 'template-forward-field)
       (should (= 3 (point)))
       (company-call 'template-forward-field)
@@ -193,10 +197,12 @@
 
 (ert-deftest company-template-removed-after-input-and-jump ()
   (with-temp-buffer
-    (insert "{ bar }")
+    (insert "{ }")
     (goto-char 2)
     (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
-      (company-template-add-field tpl 3 6)
+      (save-excursion
+        (insert " ")
+        (company-template-add-field tpl (point) "bar"))
       (company-call 'template-move-to-first tpl)
       (should (= 3 (point)))
       (dolist (c (string-to-list "tee"))
@@ -215,6 +221,18 @@
     (let ((this-command command))
       (run-hooks 'post-command-hook))))
 
+(ert-deftest company-template-c-like-templatify ()
+  (with-temp-buffer
+    (let ((text "foo(int a, short b)"))
+      (insert text)
+      (company-template-c-like-templatify text)
+      (should (equal "foo(arg0, arg1)" (buffer-string)))
+      (should (looking-at "arg0"))
+      (should (equal "int a"
+                     (overlay-get (company-template-field-at) 'display))))))
+
+;;; Elisp
+
 (defmacro company-elisp-with-buffer (contents &rest body)
   (declare (indent 0))
   `(with-temp-buffer
@@ -379,3 +397,14 @@
   (company-elisp-with-buffer
     "(defun foob ()|)"
     (should (equal "" (company-elisp 'prefix)))))
+
+;;; Clang
+
+(ert-deftest company-clang-objc-templatify ()
+  (with-temp-buffer
+    (let ((text "createBookWithTitle:andAuthor:"))
+      (insert text)
+      (company-clang-objc-templatify text)
+      (should (equal "createBookWithTitle:arg0 andAuthor:arg1" 
(buffer-string)))
+      (should (looking-at "arg0"))
+      (should (null (overlay-get (company-template-field-at) 'display))))))

commit 6a095e308b15d4dcc2358d8a2a3f88e440433a24
Author: Dmitry Gutov <address@hidden>
Date:   Sun Apr 14 01:26:58 2013 +0400

    Update NEWS
    
    Refs #11

diff --git a/NEWS.md b/NEWS.md
index a788f59..cec4fa2 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,8 @@
 
 ## Next
 
+* `company-auto-complete` is disabled by default.
+* `company-auto-complete-chars` default value includes fewer syntax classes.
 * `company-eclim` and `company-clang` do not strip argument types from fields.
 * `company-clang` expand function calls into templates for all three modes now.
 * `company-clang` supports `c++-mode` by default.

commit 320a9d09cb3b9b484286c4bc1290d4887467d58f
Author: Dmitry Gutov <address@hidden>
Date:   Sun Apr 14 00:36:16 2013 +0400

    Close #11
    
    * Turn off auto-complete by default.
    * Decrease the default auto-complete-chars list.
    * Remove company-punctuation-p, is was unused.

diff --git a/company.el b/company.el
index a1147a1..9f13518 100644
--- a/company.el
+++ b/company.el
@@ -381,7 +381,7 @@ This can be overridden by the back-end, if it returns t or 
'never to
                         'company-explicit-action-p)
                  (const :tag "On" t)))
 
-(defcustom company-auto-complete 'company-explicit-action-p
+(defcustom company-auto-complete nil
   "Determines when to auto-complete.
 If this is enabled, all characters from `company-auto-complete-chars' complete
 the selected completion.  This can also be a function."
@@ -391,7 +391,7 @@ the selected completion.  This can also be a function."
                         'company-explicit-action-p)
                  (const :tag "On" t)))
 
-(defcustom company-auto-complete-chars '(?\  ?\( ?\) ?. ?\" ?$ ?\' ?< ?| ?!)
+(defcustom company-auto-complete-chars '(?\  ?\) ?.)
   "Determines which characters trigger an automatic completion.
 See `company-auto-complete'.  If this is a string, each string character causes
 completion.  If it is a list of syntax description characters (see
@@ -901,10 +901,6 @@ can retrieve meta-data for them."
                (eq company-require-match t))
              (not (eq backend-value 'never))))))
 
-(defun company-punctuation-p (input)
-  "Return non-nil, if input starts with punctuation or parentheses."
-  (memq (char-syntax (string-to-char input)) '(?. ?\( ?\))))
-
 (defun company-auto-complete-p (input)
   "Return non-nil, if input starts with punctuation or parentheses."
   (and (if (functionp company-auto-complete)

commit 8563865558b7cf54956906c8c7b5c0dc98bced7c
Merge: d5f74fe f3813a6
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Apr 12 11:01:03 2013 -0700

    Merge pull request #1 from purcell/patch-1
    
    Fix file header line for ELPA compatibility


commit f3813a6acf3b795ac1b0e261b5c769c3791b2a87
Author: Steve Purcell <address@hidden>
Date:   Fri Apr 12 19:46:36 2013 +0200

    Fix file header line for ELPA compatibility
    
    A triple-dash is required by the `package-buffer-info` function.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index dbc142e..41cd366 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -1,4 +1,4 @@
-;;; eldoc-eval.el -- Show eldoc when using M-:
+;;; eldoc-eval.el --- Show eldoc when using M-:
 
 ;; Copyright (C) 2011 Free Software Foundation, Inc.
 

commit f77e02d4f996749f51bbc4c035c0e0d7dc16bb03
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 17:12:48 2013 +0400

    company-backends: Move semantic in front of clang
    
    semantic-mode need to be explicitly enabled, but company-clang always works 
as
    long as Clang is installed.

diff --git a/company.el b/company.el
index 09d0bb9..a1147a1 100644
--- a/company.el
+++ b/company.el
@@ -263,7 +263,7 @@ Requires Emacs 24.1 or newer."
                           (plist-get (nthcdr 4 res) :predicate)))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-clang company-semantic company-eclim
+                              company-semantic company-clang company-eclim
                               company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
                                company-keywords)

commit b46447516d13fe5b56428215b8c9d6dd35451375
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 05:37:35 2013 +0400

    Fix the template tests

diff --git a/company-tests.el b/company-tests.el
index d4ab0b7..5aa4fd8 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -175,14 +175,13 @@
 
 (ert-deftest company-template-removed-after-the-last-jump ()
   (with-temp-buffer
-    (insert "{ }")
+    (insert "{ foo foo }")
     (goto-char 2)
     (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
       (save-excursion
         (dotimes (i 2)
-          (insert " ")
-          (company-template-add-field tpl (point) "foo")
-          (forward-char 3)))
+          (search-forward "foo")
+          (company-template-add-field tpl (match-beginning 0) (match-end 0))))
       (company-call 'template-forward-field)
       (should (= 3 (point)))
       (company-call 'template-forward-field)
@@ -194,12 +193,10 @@
 
 (ert-deftest company-template-removed-after-input-and-jump ()
   (with-temp-buffer
-    (insert "{ }")
+    (insert "{ bar }")
     (goto-char 2)
     (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
-      (save-excursion
-        (insert " ")
-        (company-template-add-field tpl (point) "bar"))
+      (company-template-add-field tpl 3 6)
       (company-call 'template-move-to-first tpl)
       (should (= 3 (point)))
       (dolist (c (string-to-list "tee"))

commit 78f8b974a8f68ebc4258d5b1fcbf4b03f2223501
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 05:02:34 2013 +0400

    company-clang docstring: Clang with capital C

diff --git a/company-clang.el b/company-clang.el
index c8cfc61..60e29c1 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -228,7 +228,7 @@ Prefix files (-include ...) can be selected with
     (company-template-move-to-first templ)))
 
 (defun company-clang (command &optional arg &rest ignored)
-  "`company-mode' completion back-end for clang.
+  "`company-mode' completion back-end for Clang.
 Clang is a parser for C and ObjC.  Clang version 1.1 or newer is required.
 
 Additional command line arguments can be specified in

commit 49436401cdcb18029dd37bb41c5c8f28ffe69776
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 04:59:39 2013 +0400

    company-clang post-completion: early abort when ObjC and no ":"

diff --git a/company-clang.el b/company-clang.el
index 8b0770d..c8cfc61 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -256,11 +256,10 @@ Completions only work correctly when the buffer has been 
saved.
     (crop (and (string-match ":\\|(" arg)
                (substring arg 0 (match-beginning 0))))
     (post-completion (cond
-                      ((derived-mode-p 'objc-mode)
-                       (string-match ":" arg)
-                       (company-clang-objc-templatify arg))
-                      (t
-                       (company-template-c-like-templatify arg))))))
+                      ((not (derived-mode-p 'objc-mode))
+                       (company-template-c-like-templatify arg))
+                      ((string-match ":" arg)
+                       (company-clang-objc-templatify arg))))))
 
 (provide 'company-clang)
 ;;; company-clang.el ends here

commit 988cf9d8c21499ebdec0eb6d15ba4d92d5a2830d
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 04:34:00 2013 +0400

    Support c++-mode in company-clang; templatify calls in C and C++
    
    Close #7
    
    * company-clang--completion-pattern: Ignore (Hidden) entries.
    * company-clang--parse-output: Add function arguments to the candidate text,
    * unless we're dealing with ObjC (no problem with overloads there).
    * company-clang: Templatify function call in C in C++, same as 
`company-eclim'.
    * company-eclim--templatify: Move to company-template.el, rename to
      `company-template-c-like-templatify', don't strip the argument types from 
fields.
      Detecting where the type ends and the arg name begins is hard for C and 
C++,
      because there may be no argument name. And showing types is useful anyway.
    * company-template-add-field: Change the third argument from string to 
number.
    * company-template-move-to-first: When no fields, jump to the end.

diff --git a/NEWS.md b/NEWS.md
index 9a8fc7d..a788f59 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,11 @@
 # History of user-visible changes
 
+## Next
+
+* `company-eclim` and `company-clang` do not strip argument types from fields.
+* `company-clang` expand function calls into templates for all three modes now.
+* `company-clang` supports `c++-mode` by default.
+
 ## 2013-04-01 (0.6.7)
 
 * Two `company-elisp` tweaks.
diff --git a/company-clang.el b/company-clang.el
index 178170f..8b0770d 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -55,7 +55,7 @@ Prefix files (-include ...) can be selected with
   "A function to determine the prefix file for the current buffer."
   :type '(function :tag "Guesser function" nil))
 
-(defvar company-clang-modes '(c-mode objc-mode)
+(defvar company-clang-modes '(c-mode c++-mode objc-mode)
   "Major modes which clang may complete.")
 
 ;; prefix 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -100,15 +100,16 @@ Prefix files (-include ...) can be selected with
 
 ;; parsing 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-;; TODO: How to handle OVERLOAD and Pattern?
+;; TODO: Handle Pattern (syntactic hints would be neat).
+;; Do we ever see OVERLOAD (or OVERRIDE)?
 (defconst company-clang--completion-pattern
-  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?")
+  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?$")
 
 (defconst company-clang--error-buffer-name "*clang error*")
 
 (defvar company-clang--meta-cache nil)
 
-(defun company-clang--parse-output (prefix)
+(defun company-clang--parse-output (prefix objc)
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
                          (regexp-quote prefix)))
@@ -117,13 +118,22 @@ Prefix files (-include ...) can be selected with
     (setq company-clang--meta-cache (make-hash-table :test 'equal))
     (while (re-search-forward pattern nil t)
       (setq match (match-string-no-properties 1))
-      (let ((meta (match-string-no-properties 2)))
-        (when (and meta (not (string= match meta)))
-          (puthash match meta company-clang--meta-cache)))
       (unless (equal match "Pattern")
+        (let ((meta (match-string-no-properties 2)))
+          (when (and meta (not (string= match meta)))
+            (setq meta (company-clang--strip-formatting meta))
+            (when (and (not objc) (string-match "\\((.*)\\)" meta))
+              (setq match (concat match (match-string 1 meta))))
+            (puthash match meta company-clang--meta-cache)))
         (push match lines)))
     lines))
 
+(defun company-clang--strip-formatting (text)
+  (replace-regexp-in-string
+   "#]" " "
+   (replace-regexp-in-string "[<{[]#\\|#[>}]" "" text t)
+   t))
+
 (defun company-clang--handle-error (res args)
   (goto-char (point-min))
   (let* ((buf (get-buffer-create company-clang--error-buffer-name))
@@ -147,12 +157,13 @@ Prefix files (-include ...) can be selected with
         (goto-char (point-min))))))
 
 (defun company-clang--call-process (prefix &rest args)
-  (with-temp-buffer
-    (let ((res (apply 'call-process company-clang-executable nil t nil args)))
-      (unless (eq 0 res)
-        (company-clang--handle-error res args))
-      ;; Still try to get any useful input.
-      (company-clang--parse-output prefix))))
+  (let ((objc (derived-mode-p 'objc-mode)))
+    (with-temp-buffer
+      (let ((res (apply 'call-process company-clang-executable nil t nil 
args)))
+        (unless (eq 0 res)
+          (company-clang--handle-error res args))
+        ;; Still try to get any useful input.
+        (company-clang--parse-output prefix objc)))))
 
 (defsubst company-clang--build-location (pos)
   (save-excursion
@@ -207,8 +218,9 @@ Prefix files (-include ...) can be selected with
         (let* ((name (format "arg%d" cnt))
                (len (length name)))
           (incf end len)
-          (company-template-add-field templ (match-end 0) name)
-          (goto-char (+ (match-end 0) len))
+          (let ((pt (point)))
+            (insert name)
+            (company-template-add-field templ pt (point)))
           (when (< (point) end)
             (insert " ")
             (incf end))
@@ -240,18 +252,15 @@ Completions only work correctly when the buffer has been 
saved.
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))
     (candidates (company-clang--candidates arg))
-    (meta (let ((meta (gethash arg company-clang--meta-cache)))
-            (when meta
-              (replace-regexp-in-string
-               "#]" " "
-               (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
-               t))))
-    (crop (and (derived-mode-p 'objc-mode)
-               (string-match ":" arg)
+    (meta (gethash arg company-clang--meta-cache))
+    (crop (and (string-match ":\\|(" arg)
                (substring arg 0 (match-beginning 0))))
-    (post-completion (and (derived-mode-p 'objc-mode)
-                          (string-match ":" arg)
-                          (company-clang-objc-templatify arg)))))
+    (post-completion (cond
+                      ((derived-mode-p 'objc-mode)
+                       (string-match ":" arg)
+                       (company-clang-objc-templatify arg))
+                      (t
+                       (company-template-c-like-templatify arg))))))
 
 (provide 'company-clang)
 ;;; company-clang.el ends here
diff --git a/company-eclim.el b/company-eclim.el
index eb95187..864f550 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -142,19 +142,6 @@ eclim can only complete correctly when the buffer has been 
saved."
 (defun company-eclim--meta (candidate)
   (gethash candidate company-eclim--doc))
 
-(defun company-eclim--templatify (call)
-  (let* ((end (point))
-         (beg (- (point) (length call)))
-         (templ (company-template-declare-template beg end)))
-    (save-excursion
-      (goto-char beg)
-      (while (re-search-forward "\\([(,] ?\\)\\([^ ]+ \\)\\([^ ,)]*\\)" end t)
-        (let ((name (match-string 3)))
-          (replace-match "\\1" t)
-          (decf end (length (match-string 2)))
-          (company-template-add-field templ (point) name))))
-    (company-template-move-to-first templ)))
-
 (defun company-eclim (command &optional arg &rest ignored)
   "`company-mode' completion back-end for Eclim.
 Eclim provides access to Eclipse Java IDE features for other editors.
@@ -179,7 +166,7 @@ Completions only work correctly when the buffer has been 
saved.
     (crop (when (string-match "(" arg)
             (substring arg 0 (match-beginning 0))))
     (post-completion (when (string-match "([^)]" arg)
-                       (company-eclim--templatify arg)))))
+                       (company-template-c-like-templatify arg)))))
 
 (provide 'company-eclim)
 ;;; company-eclim.el ends here
diff --git a/company-template.el b/company-template.el
index ffceda1..fd4447f 100644
--- a/company-template.el
+++ b/company-template.el
@@ -47,9 +47,8 @@
 
 (defun company-template-move-to-first (templ)
   (interactive)
-  (let ((fields (overlay-get templ 'company-template-fields)))
-    (push-mark)
-    (goto-char (apply 'min (mapcar 'overlay-start fields)))))
+  (goto-char (overlay-start templ))
+  (company-template-forward-field))
 
 (defun company-template-forward-field ()
   (interactive)
@@ -92,15 +91,13 @@
         (delq templ company-template--buffer-templates))
   (delete-overlay templ))
 
-(defun company-template-add-field (templ pos text)
+(defun company-template-add-field (templ beg end)
+  "Add a field to template TEMPL, from BEG to END."
   (assert templ)
   (save-excursion
-    (save-excursion
-      (goto-char pos)
-      (insert text)
-      (when (> (point) (overlay-end templ))
-        (move-overlay templ (overlay-start templ) (point))))
-    (let ((ov (make-overlay pos (+ pos (length text))))
+    (when (> end (overlay-end templ))
+      (move-overlay templ (overlay-start templ) end))
+    (let ((ov (make-overlay beg end))
           (siblings (overlay-get templ 'company-template-fields)))
       ;; (overlay-put ov 'evaporate t)
       (overlay-put ov 'intangible t)
@@ -140,5 +137,21 @@
   (unless company-template--buffer-templates
     (remove-hook 'post-command-hook 'company-template-post-command t)))
 
+;; common 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-template-c-like-templatify (call)
+  (let* ((end (point))
+         (beg (- (point) (length call))))
+    (goto-char beg)
+    (when (search-forward "(" end 'move)
+      (if (eq (char-after) ?\))
+          (forward-char 1)
+        (let ((templ (company-template-declare-template beg end)))
+          (while (re-search-forward (concat " *\\([^,)]*\\)[,)]") end t)
+            (company-template-add-field templ
+                                        (match-beginning 1)
+                                        (match-end 1)))
+          (company-template-move-to-first templ))))))
+
 (provide 'company-template)
 ;;; company-template.el ends here

commit db19d03474dee277158b3ed5de088aee9d152913
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 01:01:00 2013 +0400

    Some capitalization and more uniformity

diff --git a/company-elisp.el b/company-elisp.el
index 41069cd..b55ed9f 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,4 +1,4 @@
-;;; company-elisp.el --- company-mode completion back-end for emacs-lisp-mode 
-*- lexical-binding: t -*-
+;;; company-elisp.el --- company-mode completion back-end for Emacs Lisp -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2009, 2011-2013  Free Software Foundation, Inc.
 
@@ -31,7 +31,7 @@
 (require 'find-func)
 
 (defgroup company-elisp nil
-  "Completion back-end for emacs-lisp-mode."
+  "Completion back-end for Emacs Lisp."
   :group 'company)
 
 (defcustom company-elisp-detect-function-context t
@@ -193,7 +193,7 @@ first in the candidates list."
 
 ;;;###autoload
 (defun company-elisp (command &optional arg &rest ignored)
-  "`company-mode' completion back-end for `emacs-lisp-mode'."
+  "`company-mode' completion back-end for Emacs Lisp."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-elisp))
diff --git a/company.el b/company.el
index a08b222..09d0bb9 100644
--- a/company.el
+++ b/company.el
@@ -212,22 +212,22 @@ If this many lines are not available, prefer to display 
the tooltip above."
 
 (defvar company-safe-backends
   '((company-abbrev . "Abbrev")
-    (company-clang . "clang")
+    (company-clang . "Clang")
     (company-css . "CSS")
     (company-dabbrev . "dabbrev for plain text")
     (company-dabbrev-code . "dabbrev for code")
-    (company-eclim . "eclim (an Eclipse interace)")
+    (company-eclim . "Eclim (an Eclipse interface)")
     (company-elisp . "Emacs Lisp")
     (company-etags . "etags")
     (company-files . "Files")
     (company-gtags . "GNU Global")
-    (company-ispell . "ispell")
+    (company-ispell . "Ispell")
     (company-keywords . "Programming language keywords")
     (company-nxml . "nxml")
     (company-oddmuse . "Oddmuse")
     (company-pysmell . "PySmell")
     (company-ropemacs . "ropemacs")
-    (company-semantic . "CEDET Semantic")
+    (company-semantic . "Semantic")
     (company-tempo . "Tempo templates")
     (company-xcode . "Xcode")))
 (put 'company-safe-backends 'risky-local-variable t)

commit a2724d172a55091de641baba1b6382b2d24668de
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 00:55:23 2013 +0400

    Write "tooltip" uniformly as one word

diff --git a/company.el b/company.el
index fa0b864..a08b222 100644
--- a/company.el
+++ b/company.el
@@ -91,7 +91,7 @@
      (:background "cornsilk"))
     (((class color) (min-colors 88) (background dark))
      (:background "yellow")))
-  "Face used for the tool tip.")
+  "Face used for the tooltip.")
 
 (defface company-tooltip-selection
   '((default :inherit company-tooltip)
@@ -100,11 +100,11 @@
     (((class color) (min-colors 88) (background dark))
      (:background "orange1"))
     (t (:background "green")))
-  "Face used for the selection in the tool tip.")
+  "Face used for the selection in the tooltip.")
 
 (defface company-tooltip-mouse
   '((default :inherit highlight))
-  "Face used for the tool tip item under the mouse.")
+  "Face used for the tooltip item under the mouse.")
 
 (defface company-tooltip-common
   '((default :inherit company-tooltip)
@@ -112,7 +112,7 @@
      :foreground "darkred")
     (((background dark))
      :foreground "red"))
-  "Face used for the common completion in the tool tip.")
+  "Face used for the common completion in the tooltip.")
 
 (defface company-tooltip-common-selection
   '((default :inherit company-tooltip-selection)
@@ -120,7 +120,7 @@
      :foreground "darkred")
     (((background dark))
      :foreground "red"))
-  "Face used for the selected common completion in the tool tip.")
+  "Face used for the selected common completion in the tooltip.")
 
 (defface company-preview
   '((t :background "blue4"
@@ -202,11 +202,11 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                          (function :tag "custom function" nil))))
 
 (defcustom company-tooltip-limit 10
-  "The maximum number of candidates in the tool tip"
+  "The maximum number of candidates in the tooltip"
   :type 'integer)
 
 (defcustom company-tooltip-minimum 6
-  "The minimum height of the tool tip.
+  "The minimum height of the tooltip.
 If this many lines are not available, prefer to display the tooltip above."
   :type 'integer)
 
@@ -1815,7 +1815,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
    (point) (overlay-start company-pseudo-tooltip-overlay)))
 
 (defun company-pseudo-tooltip-frontend (command)
-  "`company-mode' front-end similar to a tool-tip but based on overlays."
+  "`company-mode' front-end similar to a tooltip but based on overlays."
   (case command
     (pre-command (company-pseudo-tooltip-hide-temporarily))
     (post-command

commit 4b909bfb2baed9afaf2762b0b13b9490ad4bc246
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 00:48:12 2013 +0400

    Define groups for back-ends; remove explicit :group declarations
    
    defcustom defaults to the group last defined in the file.
    
    Refs #8

diff --git a/company-clang.el b/company-clang.el
index e014bd6..178170f 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -1,4 +1,4 @@
-;;; company-clang.el --- company-mode completion back-end for clang
+;;; company-clang.el --- company-mode completion back-end for Clang
 
 ;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
@@ -29,16 +29,18 @@
 (require 'company-template)
 (eval-when-compile (require 'cl))
 
+(defgroup company-clang nil
+  "Completion back-end for Clang."
+  :group 'company)
+
 (defcustom company-clang-executable
   (executable-find "clang")
   "Location of clang executable."
-  :group 'company-clang
   :type 'file)
 
 (defcustom company-clang-auto-save t
   "Determines whether to save the buffer when retrieving completions.
 clang can only complete correctly when the buffer has been saved."
-  :group 'company-clang
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
@@ -47,12 +49,10 @@ clang can only complete correctly when the buffer has been 
saved."
 Prefix files (-include ...) can be selected with
 `company-clang-set-prefix' or automatically through a custom
 `company-clang-prefix-guesser'."
-  :group 'company-clang
   :type '(repeat (string :tag "Argument" nil)))
 
 (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
   "A function to determine the prefix file for the current buffer."
-  :group 'company-clang
   :type '(function :tag "Guesser function" nil))
 
 (defvar company-clang-modes '(c-mode objc-mode)
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 030e3be..2b13237 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -29,6 +29,10 @@
 (require 'company-dabbrev)
 (eval-when-compile (require 'cl))
 
+(defgroup company-dabbrev-code nil
+  "dabbrev-like completion back-end for code."
+  :group 'company)
+
 (defcustom company-dabbrev-code-modes
   '(asm-mode batch-file-mode c++-mode c-mode cperl-mode csharp-mode css-mode
     emacs-lisp-mode erlang-mode espresso-mode f90-mode fortran-mode
@@ -40,7 +44,6 @@ In all these modes `company-dabbrev-code' will complete only 
symbols, not text
 in comments or strings.  In other modes `company-dabbrev-code' will pass 
control
 to other back-ends \(e.g. `company-dabbrev'\).
 Value t means complete in all modes."
-  :group 'company
   :type '(choice (repeat (symbol :tag "Major mode"))
                  (const tag "All modes" t)))
 
@@ -49,14 +52,12 @@ Value t means complete in all modes."
 If `all', search all other buffers.  If t, search buffers with the same
 major mode.
 See also `company-dabbrev-code-time-limit'."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "Same major mode" t)
                  (const :tag "All" all)))
 
 (defcustom company-dabbrev-code-time-limit .5
   "Determines how long `company-dabbrev-code' should look for matches."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
 
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 6d43ee4..1be9792 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -28,25 +28,26 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
+(defgroup company-dabbrev nil
+  "dabbrev-like completion back-end."
+  :group 'company)
+
 (defcustom company-dabbrev-other-buffers 'all
   "Determines whether `company-dabbrev' should search other buffers.
 If `all', search all other buffers.  If t, search buffers with the same
 major mode.
 See also `company-dabbrev-time-limit'."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "Same major mode" t)
                  (const :tag "All" all)))
 
 (defcustom company-dabbrev-time-limit .5
   "Determines how many seconds `company-dabbrev' should look for matches."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
 
 (defcustom company-dabbrev-char-regexp "\\sw"
   "A regular expression matching the characters `company-dabbrev' looks for."
-  :group 'company
   :type 'regexp)
 
 (defmacro company-dabrev--time-limit-while (test start limit &rest body)
diff --git a/company-eclim.el b/company-eclim.el
index ab6329e..eb95187 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,4 +1,4 @@
-;;; company-eclim.el --- company-mode completion back-end for eclim.
+;;; company-eclim.el --- company-mode completion back-end for Eclim
 
 ;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
@@ -34,6 +34,10 @@
 (require 'company-template)
 (eval-when-compile (require 'cl))
 
+(defgroup company-eclim nil
+  "Completion back-end for Eclim."
+  :group 'company)
+
 (defun company-eclim-executable-find ()
   (let (file)
     (dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
@@ -46,13 +50,11 @@
 (defcustom company-eclim-executable
   (or (executable-find "eclim") (company-eclim-executable-find))
   "Location of eclim executable."
-  :group 'company
   :type 'file)
 
 (defcustom company-eclim-auto-save t
   "Determines whether to save the buffer when retrieving completions.
 eclim can only complete correctly when the buffer has been saved."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
diff --git a/company-elisp.el b/company-elisp.el
index 2046f6a..41069cd 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -30,17 +30,19 @@
 (require 'help-mode)
 (require 'find-func)
 
+(defgroup company-elisp nil
+  "Completion back-end for emacs-lisp-mode."
+  :group 'company)
+
 (defcustom company-elisp-detect-function-context t
   "If enabled, offer Lisp functions only in appropriate contexts.
 Functions are offered for completion only after ' and \(."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
 (defcustom company-elisp-show-locals-first t
   "If enabled, locally bound variables and functions are displayed
 first in the candidates list."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
diff --git a/company-etags.el b/company-etags.el
index 2bfca80..956e294 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -28,11 +28,14 @@
 (require 'company)
 (require 'etags)
 
+(defgroup company-etags nil
+  "Completion back-end for etags."
+  :group 'company)
+
 (defcustom company-etags-use-main-table-list t
   "Always search `tags-table-list' if set.
 If this is disabled, `company-etags' will try to find the one table for each
 buffer automatically."
-  :group 'company-mode
   :type '(choice (const :tag "off" nil)
                  (const :tag "on" t)))
 
diff --git a/company-gtags.el b/company-gtags.el
index 91c3929..6b4e399 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -28,11 +28,14 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
+(defgroup company-gtags nil
+  "Completion back-end for GNU Global."
+  :group 'company)
+
 (defcustom company-gtags-executable
   (executable-find "global")
   "Location of GNU global executable."
-  :type 'string
-  :group 'company)
+  :type 'string)
 
 (define-obsolete-variable-alias
   'company-gtags-gnu-global-program-name
diff --git a/company-ispell.el b/company-ispell.el
index eee5c0c..9647f85 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -1,4 +1,4 @@
-;;; company-ispell.el --- company-mode completion back-end using ispell
+;;; company-ispell.el --- company-mode completion back-end using Ispell
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -29,10 +29,13 @@
 (require 'ispell)
 (eval-when-compile (require 'cl))
 
+(defgroup company-ispell nil
+  "Completion back-end using Ispell."
+  :group 'company)
+
 (defcustom company-ispell-dictionary nil
   "Dictionary to use for `company-ispell'.
 If nil, use `ispell-complete-word-dict'."
-  :group 'company
   :type '(choice (const :tag "default (nil)" nil)
                  (file :tag "dictionary" t)))
 
@@ -51,7 +54,7 @@ If nil, use `ispell-complete-word-dict'."
 
 ;;;###autoload
 (defun company-ispell (command &optional arg &rest ignored)
-  "`company-mode' completion back-end using ispell."
+  "`company-mode' completion back-end using Ispell."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-ispell))
diff --git a/company-ropemacs.el b/company-ropemacs.el
index 6cffbf1..17a660a 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,4 +1,4 @@
-;;; company-ropemacs.el --- company-mode completion back-end for pysmell.el
+;;; company-ropemacs.el --- company-mode completion back-end for ropemacs
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
diff --git a/company-semantic.el b/company-semantic.el
index 66a23b3..92cd178 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,4 +1,4 @@
-;;; company-semantic.el --- company-mode back-end using CEDET Semantic
+;;; company-semantic.el --- company-mode completion back-end using Semantic
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
@@ -39,9 +39,12 @@
 (declare-function semantic-tag-buffer "semantic/tag")
 (declare-function semantic-active-p "semantic")
 
+(defgroup company-semantic nil
+  "Completion back-end using Semantic."
+  :group 'company)
+
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
   "The function turning a semantic tag into doc information."
-  :group 'company
   :type 'function)
 
 (defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
diff --git a/company-xcode.el b/company-xcode.el
index 5903131..ac8d133 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -28,9 +28,12 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
+(defgroup company-xcode nil
+  "Completion back-end for Xcode projects."
+  :group 'company)
+
 (defcustom company-xcode-xcodeindex-executable (executable-find "xcodeindex")
   "Location of xcodeindex executable."
-  :group 'company-xcode
   :type 'file)
 
 (defvar company-xcode-tags nil)
@@ -50,7 +53,6 @@ valid in most contexts."
   :set (lambda (variable value)
          (set variable value)
          (company-xcode-reset))
-  :group 'company-xcode
   :type '(set (const "Category") (const "Class") (const "Class Method")
               (const "Class Variable") (const "Constant") (const "Enum")
               (const "Field") (const "Instance Method")
diff --git a/company.el b/company.el
index 86aff74..fa0b864 100644
--- a/company.el
+++ b/company.el
@@ -91,8 +91,7 @@
      (:background "cornsilk"))
     (((class color) (min-colors 88) (background dark))
      (:background "yellow")))
-  "Face used for the tool tip."
-  :group 'company)
+  "Face used for the tool tip.")
 
 (defface company-tooltip-selection
   '((default :inherit company-tooltip)
@@ -101,13 +100,11 @@
     (((class color) (min-colors 88) (background dark))
      (:background "orange1"))
     (t (:background "green")))
-  "Face used for the selection in the tool tip."
-  :group 'company)
+  "Face used for the selection in the tool tip.")
 
 (defface company-tooltip-mouse
   '((default :inherit highlight))
-  "Face used for the tool tip item under the mouse."
-  :group 'company)
+  "Face used for the tool tip item under the mouse.")
 
 (defface company-tooltip-common
   '((default :inherit company-tooltip)
@@ -115,8 +112,7 @@
      :foreground "darkred")
     (((background dark))
      :foreground "red"))
-  "Face used for the common completion in the tool tip."
-  :group 'company)
+  "Face used for the common completion in the tool tip.")
 
 (defface company-tooltip-common-selection
   '((default :inherit company-tooltip-selection)
@@ -124,36 +120,30 @@
      :foreground "darkred")
     (((background dark))
      :foreground "red"))
-  "Face used for the selected common completion in the tool tip."
-  :group 'company)
+  "Face used for the selected common completion in the tool tip.")
 
 (defface company-preview
   '((t :background "blue4"
        :foreground "wheat"))
-  "Face used for the completion preview."
-  :group 'company)
+  "Face used for the completion preview.")
 
 (defface company-preview-common
   '((t :inherit company-preview
        :foreground "red"))
-  "Face used for the common part of the completion preview."
-  :group 'company)
+  "Face used for the common part of the completion preview.")
 
 (defface company-preview-search
   '((t :inherit company-preview
        :background "blue1"))
-  "Face used for the search string in the completion preview."
-  :group 'company)
+  "Face used for the search string in the completion preview.")
 
 (defface company-echo nil
-  "Face used for completions in the echo area."
-  :group 'company)
+  "Face used for completions in the echo area.")
 
 (defface company-echo-common
   '((((background dark)) (:foreground "firebrick1"))
     (((background light)) (:background "firebrick4")))
-  "Face used for the common part of completions in the echo area."
-  :group 'company)
+  "Face used for the common part of completions in the echo area.")
 
 (defun company-frontends-set (variable value)
   ;; uniquify
@@ -197,7 +187,6 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
 `company-common', `company-selection', `company-point' and
 `company-search-string'."
   :set 'company-frontends-set
-  :group 'company
   :type '(repeat (choice (const :tag "echo" company-echo-frontend)
                          (const :tag "echo, strip common"
                                 company-echo-strip-common-frontend)
@@ -214,13 +203,11 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
 
 (defcustom company-tooltip-limit 10
   "The maximum number of candidates in the tool tip"
-  :group 'company
   :type 'integer)
 
 (defcustom company-tooltip-minimum 6
   "The minimum height of the tool tip.
 If this many lines are not available, prefer to display the tooltip above."
-  :group 'company
   :type 'integer)
 
 (defvar company-safe-backends
@@ -343,7 +330,6 @@ e.g. to expand a snippet.
 The back-end should return nil for all commands it does not support or
 does not know about.  It should also be callable interactively and use
 `company-begin-backend' to start itself in that case."
-  :group 'company
   :type `(repeat
           (choice
            :tag "Back-end"
@@ -363,14 +349,12 @@ does not know about.  It should also be callable 
interactively and use
   "Hook run when company starts completing.
 The hook is called with one argument that is non-nil if the completion was
 started manually."
-  :group 'company
   :type 'hook)
 
 (defcustom company-completion-cancelled-hook nil
   "Hook run when company cancels completing.
 The hook is called with one argument that is non-nil if the completion was
 aborted manually."
-  :group 'company
   :type 'hook)
 
 (defcustom company-completion-finished-hook nil
@@ -379,12 +363,10 @@ The hook is called with the selected candidate as an 
argument.
 
 If you indend to use it to post-process candidates from a specific back-end,
 consider using the `post-completion' command instead."
-  :group 'company
   :type 'hook)
 
 (defcustom company-minimum-prefix-length 3
   "The minimum prefix length for automatic completion."
-  :group 'company
   :type '(integer :tag "prefix length"))
 
 (defcustom company-require-match 'company-explicit-action-p
@@ -393,7 +375,6 @@ This can be a function do determine if a match is required.
 
 This can be overridden by the back-end, if it returns t or 'never to
 'require-match.  `company-auto-complete' also takes precedence over this."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
                  (const :tag "On, if user interaction took place"
@@ -404,7 +385,6 @@ This can be overridden by the back-end, if it returns t or 
'never to
   "Determines when to auto-complete.
 If this is enabled, all characters from `company-auto-complete-chars' complete
 the selected completion.  This can also be a function."
-  :group 'company
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
                  (const :tag "On, if user interaction took place"
@@ -421,7 +401,6 @@ This can also be a function, which is called with the new 
input and should
 return non-nil if company should auto-complete.
 
 A character that is part of a valid candidate never triggers auto-completion."
-  :group 'company
   :type '(choice (string :tag "Characters")
                  (set :tag "Syntax"
                       (const :tag "Whitespace" ?\ )
@@ -444,7 +423,6 @@ A character that is part of a valid candidate never 
triggers auto-completion."
   "The idle delay in seconds until automatic completions starts.
 A value of nil means never complete automatically, t means complete
 immediately when a prefix of `company-minimum-prefix-length' is reached."
-  :group 'company
   :type '(choice (const :tag "never (nil)" nil)
                  (const :tag "immediate (t)" t)
                  (number :tag "seconds")))
@@ -455,14 +433,12 @@ If this is t, it will complete after any command.  See 
`company-idle-delay'.
 
 Alternatively any command with a non-nil 'company-begin property is treated as
 if it was on this list."
-  :group 'company
   :type '(choice (const :tag "Any command" t)
                  (const :tag "Self insert command" '(self-insert-command))
                  (repeat :tag "Commands" function)))
 
 (defcustom company-show-numbers nil
   "If enabled, show quick-access numbers for the first ten candidates."
-  :group 'company
   :type '(choice (const :tag "off" nil)
                  (const :tag "on" t)))
 

commit 898d24473460332ab92bea5367b93ce6b8aa86f8
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 10 00:17:03 2013 +0400

    Remove the As

diff --git a/company-abbrev.el b/company-abbrev.el
index a28c88d..0c4e327 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -1,4 +1,4 @@
-;;; company-abbrev.el --- A company-mode completion back-end for abbrev
+;;; company-abbrev.el --- company-mode completion back-end for abbrev
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -35,7 +35,7 @@
 
 ;;;###autoload
 (defun company-abbrev (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for abbrev."
+  "`company-mode' completion back-end for abbrev."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-abbrev
diff --git a/company-clang.el b/company-clang.el
index 6844bb0..e014bd6 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -1,4 +1,4 @@
-;;; company-clang.el --- A company-mode completion back-end for clang
+;;; company-clang.el --- company-mode completion back-end for clang
 
 ;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
@@ -216,7 +216,7 @@ Prefix files (-include ...) can be selected with
     (company-template-move-to-first templ)))
 
 (defun company-clang (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for clang.
+  "`company-mode' completion back-end for clang.
 Clang is a parser for C and ObjC.  Clang version 1.1 or newer is required.
 
 Additional command line arguments can be specified in
diff --git a/company-css.el b/company-css.el
index 6546a10..11e195a 100644
--- a/company-css.el
+++ b/company-css.el
@@ -1,4 +1,4 @@
-;;; company-css.el --- A company-mode completion back-end for css-mode
+;;; company-css.el --- company-mode completion back-end for css-mode
 
 ;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
 
@@ -278,7 +278,7 @@ Returns \"\" if no property found, but feasible at this 
position."
 
 ;;;###autoload
 (defun company-css (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `css-mode'."
+  "`company-mode' completion back-end for `css-mode'."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-css))
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index b98c17d..030e3be 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -1,4 +1,4 @@
-;;; company-dabbrev-code.el --- A dabbrev-like company-mode back-end for code
+;;; company-dabbrev-code.el --- dabbrev-like company-mode back-end for code
 
 ;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
 
@@ -68,7 +68,7 @@ See also `company-dabbrev-code-time-limit'."
 
 ;;;###autoload
 (defun company-dabbrev-code (command &optional arg &rest ignored)
-  "A dabbrev-like `company-mode' back-end for code.
+  "dabbrev-like `company-mode' back-end for code.
 The back-end looks for all symbols in the current buffer that aren't in
 comments or strings."
   (interactive (list 'interactive))
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 5f43b83..6d43ee4 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -1,4 +1,4 @@
-;;; company-dabbrev.el --- A dabbrev-like company-mode completion back-end
+;;; company-dabbrev.el --- dabbrev-like company-mode completion back-end
 
 ;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
 
@@ -109,7 +109,7 @@ See also `company-dabbrev-time-limit'."
 
 ;;;###autoload
 (defun company-dabbrev (command &optional arg &rest ignored)
-  "A dabbrev-like `company-mode' completion back-end."
+  "dabbrev-like `company-mode' completion back-end."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-dabbrev))
diff --git a/company-eclim.el b/company-eclim.el
index b9ac242..ab6329e 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,4 +1,4 @@
-;;; company-eclim.el --- A company-mode completion back-end for eclim.
+;;; company-eclim.el --- company-mode completion back-end for eclim.
 
 ;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
@@ -154,7 +154,7 @@ eclim can only complete correctly when the buffer has been 
saved."
     (company-template-move-to-first templ)))
 
 (defun company-eclim (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for Eclim.
+  "`company-mode' completion back-end for Eclim.
 Eclim provides access to Eclipse Java IDE features for other editors.
 
 Eclim version 1.7.13 or newer (?) is required.
diff --git a/company-elisp.el b/company-elisp.el
index 338acc5..2046f6a 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,4 +1,4 @@
-;;; company-elisp.el --- A company-mode completion back-end for 
emacs-lisp-mode -*- lexical-binding: t -*-
+;;; company-elisp.el --- company-mode completion back-end for emacs-lisp-mode 
-*- lexical-binding: t -*-
 
 ;; Copyright (C) 2009, 2011-2013  Free Software Foundation, Inc.
 
@@ -191,7 +191,7 @@ first in the candidates list."
 
 ;;;###autoload
 (defun company-elisp (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `emacs-lisp-mode'."
+  "`company-mode' completion back-end for `emacs-lisp-mode'."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-elisp))
diff --git a/company-etags.el b/company-etags.el
index 88b9fca..2bfca80 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -1,4 +1,4 @@
-;;; company-etags.el --- A company-mode completion back-end for etags
+;;; company-etags.el --- company-mode completion back-end for etags
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -66,7 +66,7 @@ buffer automatically."
 
 ;;;###autoload
 (defun company-etags (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for etags."
+  "`company-mode' completion back-end for etags."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-etags))
diff --git a/company-files.el b/company-files.el
index ebb11c0..3b7a7d0 100644
--- a/company-files.el
+++ b/company-files.el
@@ -1,4 +1,4 @@
-;;; company-files.el --- A company-mode completion back-end for file names
+;;; company-files.el --- company-mode completion back-end for file names
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
@@ -75,7 +75,7 @@
 
 ;;;###autoload
 (defun company-files (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end existing file names."
+  "`company-mode' completion back-end existing file names."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-files))
diff --git a/company-gtags.el b/company-gtags.el
index 59ad7c8..91c3929 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -1,4 +1,4 @@
-;;; company-gtags.el --- A company-mode completion back-end for GNU Global
+;;; company-gtags.el --- company-mode completion back-end for GNU Global
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -70,7 +70,7 @@
 
 ;;;###autoload
 (defun company-gtags (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for GNU Global."
+  "`company-mode' completion back-end for GNU Global."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-gtags))
diff --git a/company-ispell.el b/company-ispell.el
index 8a73988..eee5c0c 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -1,4 +1,4 @@
-;;; company-ispell.el --- A company-mode completion back-end using ispell
+;;; company-ispell.el --- company-mode completion back-end using ispell
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -51,7 +51,7 @@ If nil, use `ispell-complete-word-dict'."
 
 ;;;###autoload
 (defun company-ispell (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end using ispell."
+  "`company-mode' completion back-end using ispell."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-ispell))
diff --git a/company-keywords.el b/company-keywords.el
index 75d37d6..750540c 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -216,7 +216,7 @@
 
 ;;;###autoload
 (defun company-keywords (command &optional arg &rest ignored)
-  "A `company-mode' back-end for programming language keywords."
+  "`company-mode' back-end for programming language keywords."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-keywords))
diff --git a/company-nxml.el b/company-nxml.el
index 33d6f7b..62e6e31 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -1,4 +1,4 @@
-;;; company-nxml.el --- A company-mode completion back-end for nxml-mode
+;;; company-nxml.el --- company-mode completion back-end for nxml-mode
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
@@ -121,7 +121,7 @@
 
 ;;;###autoload
 (defun company-nxml (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `nxml-mode'."
+  "`company-mode' completion back-end for `nxml-mode'."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-nxml))
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 8d60a2e..b76c87e 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -1,4 +1,4 @@
-;;; company-oddmuse.el --- A company-mode completion back-end for oddmuse-mode
+;;; company-oddmuse.el --- company-mode completion back-end for oddmuse-mode
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -42,7 +42,7 @@
 
 ;;;###autoload
 (defun company-oddmuse (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `oddmuse-mode'."
+  "`company-mode' completion back-end for `oddmuse-mode'."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-oddmuse))
diff --git a/company-pysmell.el b/company-pysmell.el
index fe36eef..063d8ea 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -1,4 +1,4 @@
-;;; company-pysmell.el --- A company-mode completion back-end for pysmell.el
+;;; company-pysmell.el --- company-mode completion back-end for pysmell.el
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -53,7 +53,7 @@
 
 ;;;###autoload
 (defun company-pysmell (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for pysmell.
+  "`company-mode' completion back-end for pysmell.
 This requires pysmell.el and pymacs.el."
   (interactive (list 'interactive))
   (case command
diff --git a/company-ropemacs.el b/company-ropemacs.el
index bba9bcb..6cffbf1 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,4 +1,4 @@
-;;; company-ropemacs.el --- A company-mode completion back-end for pysmell.el
+;;; company-ropemacs.el --- company-mode completion back-end for pysmell.el
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
@@ -57,7 +57,7 @@
       (cons (elt location 0) (elt location 1)))))
 
 (defun company-ropemacs (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for ropemacs."
+  "`company-mode' completion back-end for ropemacs."
   (interactive (list 'interactive))
   (case command
     (init (when (and (derived-mode-p 'python-mode)
diff --git a/company-semantic.el b/company-semantic.el
index c376710..66a23b3 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,4 +1,4 @@
-;;; company-semantic.el --- A company-mode back-end using CEDET Semantic
+;;; company-semantic.el --- company-mode back-end using CEDET Semantic
 
 ;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
@@ -111,7 +111,7 @@ Symbols are chained by \".\" or \"->\"."
 
 ;;;###autoload
 (defun company-semantic (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end using CEDET Semantic."
+  "`company-mode' completion back-end using CEDET Semantic."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-semantic))
diff --git a/company-tempo.el b/company-tempo.el
index 1dda49e..feea698 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -1,4 +1,4 @@
-;;; company-tempo.el --- A company-mode completion back-end for tempo
+;;; company-tempo.el --- company-mode completion back-end for tempo
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -48,7 +48,7 @@
 
 ;;;###autoload
 (defun company-tempo (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for tempo."
+  "`company-mode' completion back-end for tempo."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-tempo
diff --git a/company-xcode.el b/company-xcode.el
index b558fe8..5903131 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -1,4 +1,4 @@
-;;; company-xcode.el --- A company-mode completion back-end for Xcode projects
+;;; company-xcode.el --- company-mode completion back-end for Xcode projects
 
 ;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
 
@@ -105,7 +105,7 @@ valid in most contexts."
                         company-xcode-tags))))))
 ;;;###autoload
 (defun company-xcode (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for Xcode projects."
+  "`company-mode' completion back-end for Xcode projects."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-xcode))
diff --git a/company.el b/company.el
index cbfa62f..86aff74 100644
--- a/company.el
+++ b/company.el
@@ -1839,7 +1839,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
    (point) (overlay-start company-pseudo-tooltip-overlay)))
 
 (defun company-pseudo-tooltip-frontend (command)
-  "A `company-mode' front-end similar to a tool-tip but based on overlays."
+  "`company-mode' front-end similar to a tool-tip but based on overlays."
   (case command
     (pre-command (company-pseudo-tooltip-hide-temporarily))
     (post-command
@@ -1909,7 +1909,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (setq company-preview-overlay nil)))
 
 (defun company-preview-frontend (command)
-  "A `company-mode' front-end showing the selection as if it had been 
inserted."
+  "`company-mode' front-end showing the selection as if it had been inserted."
   (case command
     (pre-command (company-preview-hide))
     (post-command (company-preview-show-at-point (point)))
@@ -2013,19 +2013,19 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (company-echo-show)))
 
 (defun company-echo-frontend (command)
-  "A `company-mode' front-end showing the candidates in the echo area."
+  "`company-mode' front-end showing the candidates in the echo area."
   (case command
     (post-command (company-echo-show-soon 'company-echo-format))
     (hide (company-echo-hide))))
 
 (defun company-echo-strip-common-frontend (command)
-  "A `company-mode' front-end showing the candidates in the echo area."
+  "`company-mode' front-end showing the candidates in the echo area."
   (case command
     (post-command (company-echo-show-soon 'company-echo-strip-common-format))
     (hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
-  "A `company-mode' front-end showing the documentation in the echo area."
+  "`company-mode' front-end showing the documentation in the echo area."
   (case command
     (post-command (company-echo-show-when-idle 'company-fetch-metadata))
     (hide (company-echo-hide))))

commit 5c3f8acb7acb3214cf693e9842c5288fe810c5dc
Merge: 7e80033 ae0e0c7
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 9 09:23:01 2013 -0700

    Merge pull request #95 from ruediger/typed-array-externs
    
    Typed array externs and console object


commit ae0e0c73b0bc0ad447d34b4900320e4f934de377
Author: Rüdiger Sonderfeld <address@hidden>
Date:   Tue Apr 9 18:20:02 2013 +0200

    Typed Array: remove TypedArray and ArrayBufferView.
    
    They are just interfaces.
    
    Signed-off-by: Rüdiger Sonderfeld <address@hidden>

diff --git a/js2-mode.el b/js2-mode.el
index 75c3214..06824bd 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -168,7 +168,7 @@
             XPathResult XMLHttpRequest
 
             ;; Khronos Typed Array Specification
-            ArrayBuffer ArrayBufferView TypedArray Uint8ClampedArray DataView
+            ArrayBuffer Uint8ClampedArray DataView
             Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
             Float32Array Float64Array
 

commit 81f654a44addbe4376c18c9f7fc401b8103a606f
Author: Rüdiger Sonderfeld <address@hidden>
Date:   Tue Apr 9 16:51:59 2013 +0200

    Add console Object to browser externs.
    
    console is provided by at least Firefox and Chrome.
    
    Signed-off-by: Rüdiger Sonderfeld <address@hidden>

diff --git a/js2-mode.el b/js2-mode.el
index 15cb0c5..75c3214 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -170,7 +170,10 @@
             ;; Khronos Typed Array Specification
             ArrayBuffer ArrayBufferView TypedArray Uint8ClampedArray DataView
             Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
-            Float32Array Float64Array))
+            Float32Array Float64Array
+
+            ;; console object.  Provided by at least Chrome and Firefox.
+            console))
   "Browser externs.
 You can cause these to be included or excluded with the custom
 variable `js2-include-browser-externs'.")

commit d5837b4f4aa8c9e393579432afaf14716b608309
Author: Rüdiger Sonderfeld <address@hidden>
Date:   Tue Apr 9 16:51:19 2013 +0200

    Add Typed Array Spec Externs.
    
    Signed-off-by: Rüdiger Sonderfeld <address@hidden>

diff --git a/js2-mode.el b/js2-mode.el
index 0853bac..15cb0c5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -165,7 +165,12 @@
             DocumentRange Range RangeException
 
             ;; W3C XML
-            XPathResult XMLHttpRequest))
+            XPathResult XMLHttpRequest
+
+            ;; Khronos Typed Array Specification
+            ArrayBuffer ArrayBufferView TypedArray Uint8ClampedArray DataView
+            Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array
+            Float32Array Float64Array))
   "Browser externs.
 You can cause these to be included or excluded with the custom
 variable `js2-include-browser-externs'.")

commit 8774bc9596333d838cd941e0d8b27065b8002894
Author: Leo Liu <address@hidden>
Date:   Fri Apr 5 15:53:43 2013 +0800

    Fix #6: do not override split-window-preferred-function
    
    Use new user variable ggtags-split-window-function instead for
    customised behaviour.

diff --git a/ggtags.el b/ggtags.el
index 4d8671b..a41079f 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -93,6 +93,11 @@ If nil, use Emacs default."
                  integer)
   :group 'ggtags)
 
+(defcustom ggtags-split-window-function split-window-preferred-function
+  "A function to control how ggtags pops up the auxiliary window."
+  :type 'function
+  :group 'ggtags)
+
 (defvar ggtags-cache nil)               ; (ROOT TABLE DIRTY TIMESTAMP)
 
 (defvar ggtags-current-tag-name nil)
@@ -235,8 +240,7 @@ When called with prefix, ask the name and kind of tag."
   (ggtags-check-root-directory)
   (ggtags-navigation-mode +1)
   (ring-insert find-tag-marker-ring (point-marker))
-  (let ((split-window-preferred-function
-         (lambda (w) (split-window (frame-root-window w))))
+  (let ((split-window-preferred-function ggtags-split-window-function)
         (default-directory (ggtags-root-directory)))
     (compilation-start
      (if (or verbose (not buffer-file-name))
@@ -256,8 +260,7 @@ When called with prefix, ask the name and kind of tag."
   (interactive)
   (ggtags-ensure-global-buffer
     (ggtags-navigation-mode +1)
-    (let ((split-window-preferred-function
-           (lambda (w) (split-window (frame-root-window w)))))
+    (let ((split-window-preferred-function ggtags-split-window-function))
       (compile-goto-error))))
 
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)

commit 8dceda389115b397de48becc4b68a64f4dc4bbab
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 5 00:07:27 2013 +0400

    Bump version in company.el

diff --git a/company.el b/company.el
index 13c61ee..cbfa62f 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.6
+;; Version: 0.6.7
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit ed643b908e0674ffc1aec9af2df5380ddfcedbb8
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 5 00:02:43 2013 +0400

    company-elisp--candidates-predicate: Consider bindings without values
    
    * company-elisp-with-buffer: Bind company-elisp-detect-function-context to 
t.
    * Release 0.6.7.

diff --git a/NEWS.md b/NEWS.md
index b6000b7..9a8fc7d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,9 @@
 # History of user-visible changes
 
+## 2013-04-01 (0.6.7)
+
+* Two `company-elisp` tweaks.
+
 ## 2013-04-01 (0.6.6)
 
 * `company-elisp` doesn't offer completions when typing the name and the
diff --git a/company-elisp.el b/company-elisp.el
index 000f30c..338acc5 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -157,24 +157,29 @@ first in the candidates list."
 
 (defun company-elisp--candidates-predicate (prefix)
   (let* ((completion-ignore-case nil)
-         (before (char-before (- (point) (length prefix)))))
+         (beg (- (point) (length prefix)))
+         (before (char-before beg)))
     (if (and company-elisp-detect-function-context
              (not (memq before '(?' ?`))))
         (if (and (eq before ?\()
                  (not
                   (save-excursion
                     (ignore-errors
-                      (up-list -2)
-                      (and (save-excursion
-                             (forward-char 1)
-                             (looking-at "[ \t\n]*("))
-                           (prog1 (search-backward "(")
-                             (forward-char 1))
-                           (looking-at company-elisp-var-binding-regexp))))))
+                      (goto-char (1- beg))
+                      (or (company-elisp--before-binding-varlist-p)
+                          (progn
+                            (up-list -1)
+                            (company-elisp--before-binding-varlist-p)))))))
             'fboundp
           'boundp)
       'company-elisp--predicate)))
 
+(defun company-elisp--before-binding-varlist-p ()
+  (save-excursion
+    (and (prog1 (search-backward "(")
+           (forward-char 1))
+         (looking-at company-elisp-var-binding-regexp))))
+
 (defun company-elisp--doc (symbol)
   (let* ((symbol (intern symbol))
          (doc (if (fboundp symbol)
diff --git a/company-tests.el b/company-tests.el
index fdc2189..d4ab0b7 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -225,37 +225,34 @@
      (setq major-mode 'emacs-lisp-mode)
      (re-search-backward "|")
      (replace-match "")
-     ,@body))
+     (let ((company-elisp-detect-function-context t))
+       ,@body)))
 
 (ert-deftest company-elisp-candidates-predicate ()
   (company-elisp-with-buffer
     "(foo ba|)"
-    (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp--candidates-predicate "ba"))
+    (should (eq (company-elisp--candidates-predicate "ba")
                 'boundp))
     (should (eq (let (company-elisp-detect-function-context)
                   (company-elisp--candidates-predicate "ba"))
                 'company-elisp--predicate)))
   (company-elisp-with-buffer
     "(foo| )"
-    (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp--candidates-predicate "foo"))
+    (should (eq (company-elisp--candidates-predicate "foo")
                 'fboundp))
     (should (eq (let (company-elisp-detect-function-context)
                   (company-elisp--candidates-predicate "foo"))
                 'company-elisp--predicate)))
   (company-elisp-with-buffer
     "(foo 'b|)"
-    (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp--candidates-predicate "b"))
+    (should (eq (company-elisp--candidates-predicate "b")
                 'company-elisp--predicate))))
 
 (ert-deftest company-elisp-candidates-predicate-in-docstring ()
   (company-elisp-with-buffer
    "(def foo () \"Doo be doo `ide|"
    (should (eq 'company-elisp--predicate
-               (let ((company-elisp-detect-function-context t))
-                 (company-elisp--candidates-predicate "ide"))))))
+               (company-elisp--candidates-predicate "ide")))))
 
 ;; This one's also an integration test.
 (ert-deftest company-elisp-candidates-recognizes-binding-form ()
@@ -273,6 +270,16 @@
       (should (equal '("when")
                      (company-elisp-candidates "wh"))))))
 
+(ert-deftest company-elisp-candidates-predicate-binding-without-value ()
+  (loop for (text prefix predicate) in '(("(let (foo|" "foo" boundp)
+                                         ("(let (foo (bar|" "bar" boundp)
+                                         ("(let (foo) (bar|" "bar" fboundp))
+        do
+        (eval `(company-elisp-with-buffer
+                 ,text
+                 (should (eq ',predicate
+                             (company-elisp--candidates-predicate 
,prefix)))))))
+
 (ert-deftest company-elisp-finds-vars ()
   (let ((obarray [boo bar baz backquote])
         (boo t)

commit 7e80033bef50bd077b335543275736a552889104
Merge: f713d6f da7ddff
Author: Dmitry Gutov <address@hidden>
Date:   Thu Apr 4 08:34:19 2013 -0700

    Merge pull request #93 from ruediger/use-asm
    
    Treat "use asm" as having side effects.


commit da7ddff57963996119c50d75b89db70fc83a5888
Author: Rüdiger Sonderfeld <address@hidden>
Date:   Thu Apr 4 15:16:27 2013 +0200

    Treat "use asm" as having side effects.
    
    Support for asm.js.  Change in `js2-node-has-side-effects'.
    
    Signed-off-by: Rüdiger Sonderfeld <address@hidden>

diff --git a/js2-mode.el b/js2-mode.el
index 10655c5..0853bac 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4601,7 +4601,7 @@ You should use `js2-print-tree' instead of this function."
         (let ((expr (js2-expr-stmt-node-expr node)))
           (or (js2-node-has-side-effects expr)
               (when (js2-string-node-p expr)
-                (string= "use strict" (js2-string-node-value expr))))))
+                (member (js2-string-node-value expr) '("use strict" "use 
asm"))))))
        ((= tt js2-COMMA)
         (js2-node-has-side-effects (js2-infix-node-right node)))
        ((or (= tt js2-AND)

commit 6422b3e7efb554bbfc8b9d9f051402d9097573b1
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 3 11:16:33 2013 +0400

    company-elisp--candidates-predicate: Consider backquote

diff --git a/company-elisp.el b/company-elisp.el
index faab0b0..000f30c 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -159,7 +159,7 @@ first in the candidates list."
   (let* ((completion-ignore-case nil)
          (before (char-before (- (point) (length prefix)))))
     (if (and company-elisp-detect-function-context
-             (not (eq before ?')))
+             (not (memq before '(?' ?`))))
         (if (and (eq before ?\()
                  (not
                   (save-excursion
diff --git a/company-tests.el b/company-tests.el
index 33437d8..fdc2189 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -250,6 +250,13 @@
                   (company-elisp--candidates-predicate "b"))
                 'company-elisp--predicate))))
 
+(ert-deftest company-elisp-candidates-predicate-in-docstring ()
+  (company-elisp-with-buffer
+   "(def foo () \"Doo be doo `ide|"
+   (should (eq 'company-elisp--predicate
+               (let ((company-elisp-detect-function-context t))
+                 (company-elisp--candidates-predicate "ide"))))))
+
 ;; This one's also an integration test.
 (ert-deftest company-elisp-candidates-recognizes-binding-form ()
   (let ((company-elisp-detect-function-context t)

commit 33d2acd2a8fa3ac7e6cb5f712baa8507662cf2c8
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 1 09:04:45 2013 +0400

    company-manual-begin: Clear `explicit-action` when no candidates

diff --git a/NEWS.md b/NEWS.md
index 4a46891..b6000b7 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,6 @@
 # History of user-visible changes
 
-## Next
+## 2013-04-01 (0.6.6)
 
 * `company-elisp` doesn't offer completions when typing the name and the
   arguments of a new function or macro definition, allowing to fall back to
diff --git a/company-tests.el b/company-tests.el
index 811e4cc..33437d8 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -148,6 +148,15 @@
         (company-call 'self-insert-command 1))
       (should (string= "ab " (buffer-string))))))
 
+(ert-deftest company-clears-explicit-action-when-no-matches ()
+  (with-temp-buffer
+    (company-mode)
+    (let (company-frontends
+          company-backends)
+      (company-call 'manual-begin) ;; fails
+      (should (null company-candidates))
+      (should (null (company-explicit-action-p))))))
+
 (ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
   (with-temp-buffer
     (save-window-excursion
diff --git a/company.el b/company.el
index 35b0780..13c61ee 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.5
+;; Version: 0.6.6
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
@@ -895,7 +895,10 @@ can retrieve meta-data for them."
 (defun company-manual-begin ()
   (interactive)
   (setq company--explicit-action t)
-  (company-auto-begin))
+  (unwind-protect
+      (company-auto-begin)
+    (unless company-candidates
+      (setq company--explicit-action nil))))
 
 (defun company-other-backend (&optional backward)
   (interactive (list current-prefix-arg))

commit 8a23e481449111d0050e0250039ae8a0558807c0
Author: Dmitry Gutov <address@hidden>
Date:   Sun Mar 31 22:52:39 2013 +0400

    company-elisp: Don't complete defun name or arglist

diff --git a/NEWS.md b/NEWS.md
index 6297652..4a46891 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,11 @@
 # History of user-visible changes
 
+## Next
+
+* `company-elisp` doesn't offer completions when typing the name and the
+  arguments of a new function or macro definition, allowing to fall back to
+  other back-ends like `company-dabbrev-code`.
+
 ## 2013-03-30 (0.6.5)
 
 * Fixed keybindings when running in a terminal.
diff --git a/company-elisp.el b/company-elisp.el
index 53b4885..faab0b0 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -47,8 +47,9 @@ first in the candidates list."
 (defun company-elisp--prefix ()
   (let ((prefix (company-grab-symbol)))
     (if prefix
-        (unless (and (company-in-string-or-comment)
-                     (/= (char-before (- (point) (length prefix))) ?`))
+        (when (if (company-in-string-or-comment)
+                  (= (char-before (- (point) (length prefix))) ?`)
+                (company-elisp--should-complete))
           prefix)
       'stop)))
 
@@ -58,23 +59,49 @@ first in the candidates list."
       (facep symbol)
       (featurep symbol)))
 
+(defun company-elisp--fns-regexp (&rest names)
+  (concat "\\_<\\(?:cl-\\)?" (regexp-opt names) "\\*?\\_>"))
+
 (defvar company-elisp-parse-limit 30)
 (defvar company-elisp-parse-depth 100)
 
+(defvar company-elisp-defun-names '("defun" "defmacro" "defsubst"))
+
 (defvar company-elisp-var-binding-regexp
-  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("let" "defun" "defmacro" "defsubst"
-                                           "lambda" "lexical-let"))
-          "\\*?\\_>")
+  (apply #'company-elisp--fns-regexp "let" "lambda" "lexical-let"
+         company-elisp-defun-names)
   "Regular expression matching head of a multiple variable bindings form.")
 
 (defvar company-elisp-var-binding-regexp-1
-  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("dolist" "dotimes")) "\\_>")
+  (company-elisp--fns-regexp "dolist" "dotimes")
   "Regular expression matching head of a form with one variable binding.")
 
 (defvar company-elisp-fun-binding-regexp
-  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("flet" "labels")) "\\*?\\_>")
+  (company-elisp--fns-regexp "flet" "labels")
   "Regular expression matching head of a function bindings form.")
 
+(defvar company-elisp-defuns-regexp
+  (concat "([ \t\n]*"
+          (apply #'company-elisp--fns-regexp company-elisp-defun-names)))
+
+(defun company-elisp--should-complete ()
+  (let ((start (point))
+        (depth (car (syntax-ppss))))
+    (not
+     (when (> depth 0)
+       (save-excursion
+         (up-list (- depth))
+         (when (looking-at company-elisp-defuns-regexp)
+           (forward-char)
+           (forward-sexp 1)
+           (unless (= (point) start)
+             (condition-case nil
+                 (let ((args-end (scan-sexps (point) 2)))
+                   (or (null args-end)
+                       (> args-end start)))
+               (scan-error
+                t)))))))))
+
 (defun company-elisp--locals (prefix functions-p)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
diff --git a/company-tests.el b/company-tests.el
index 011b67f..811e4cc 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -213,6 +213,7 @@
   (declare (indent 0))
   `(with-temp-buffer
      (insert ,contents)
+     (setq major-mode 'emacs-lisp-mode)
      (re-search-backward "|")
      (replace-match "")
      ,@body))
@@ -332,3 +333,29 @@
     (let ((obarray [float-pi])
           (company-elisp-show-locals-first t))
       (should (equal '("float-pi") (company-elisp-candidates "f"))))))
+
+(ert-deftest company-elisp-shouldnt-complete-defun-name ()
+  (company-elisp-with-buffer
+    "(defun foob|)"
+    (should (null (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-should-complete-def-call ()
+  (company-elisp-with-buffer
+    "(defu|"
+    (should (equal "defu" (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-should-complete-in-defvar ()
+  ;; It will also complete the var name, at least for now.
+  (company-elisp-with-buffer
+    "(defvar abc de|"
+    (should (equal "de" (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-shouldnt-complete-in-defun-arglist ()
+  (company-elisp-with-buffer
+    "(defsubst foobar (ba|"
+    (should (null (company-elisp 'prefix)))))
+
+(ert-deftest company-elisp-prefix-in-defun-body ()
+  (company-elisp-with-buffer
+    "(defun foob ()|)"
+    (should (equal "" (company-elisp 'prefix)))))

commit 0259e7b94c7c6c00072454ade0716cb5d3646dbc
Author: Dmitry Gutov <address@hidden>
Date:   Sun Mar 31 19:58:49 2013 +0400

    company-grab-lisp-symbol -> company-elisp--prefix; mark other privates

diff --git a/company-elisp.el b/company-elisp.el
index a27edae..53b4885 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -44,7 +44,7 @@ first in the candidates list."
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
-(defun company-grab-lisp-symbol ()
+(defun company-elisp--prefix ()
   (let ((prefix (company-grab-symbol)))
     (if prefix
         (unless (and (company-in-string-or-comment)
@@ -52,7 +52,7 @@ first in the candidates list."
           prefix)
       'stop)))
 
-(defun company-elisp-predicate (symbol)
+(defun company-elisp--predicate (symbol)
   (or (boundp symbol)
       (fboundp symbol)
       (facep symbol)
@@ -75,7 +75,7 @@ first in the candidates list."
   (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("flet" "labels")) "\\*?\\_>")
   "Regular expression matching head of a function bindings form.")
 
-(defun company-elisp-locals (prefix functions-p)
+(defun company-elisp--locals (prefix functions-p)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
         (pos (point))
@@ -114,9 +114,9 @@ first in the candidates list."
     res))
 
 (defun company-elisp-candidates (prefix)
-  (let* ((predicate (company-elisp-candidates-predicate prefix))
-         (locals (company-elisp-locals prefix (eq predicate 'fboundp)))
-         (globals (company-elisp-globals prefix predicate))
+  (let* ((predicate (company-elisp--candidates-predicate prefix))
+         (locals (company-elisp--locals prefix (eq predicate 'fboundp)))
+         (globals (company-elisp--globals prefix predicate))
          (locals (loop for local in locals
                        when (not (member local globals))
                        collect local)))
@@ -125,10 +125,10 @@ first in the candidates list."
                 (sort globals 'string<))
       (append locals globals))))
 
-(defun company-elisp-globals (prefix predicate)
+(defun company-elisp--globals (prefix predicate)
   (all-completions prefix obarray predicate))
 
-(defun company-elisp-candidates-predicate (prefix)
+(defun company-elisp--candidates-predicate (prefix)
   (let* ((completion-ignore-case nil)
          (before (char-before (- (point) (length prefix)))))
     (if (and company-elisp-detect-function-context
@@ -146,9 +146,9 @@ first in the candidates list."
                            (looking-at company-elisp-var-binding-regexp))))))
             'fboundp
           'boundp)
-      'company-elisp-predicate)))
+      'company-elisp--predicate)))
 
-(defun company-elisp-doc (symbol)
+(defun company-elisp--doc (symbol)
   (let* ((symbol (intern symbol))
          (doc (if (fboundp symbol)
                   (documentation symbol t)
@@ -164,10 +164,10 @@ first in the candidates list."
   (case command
     (interactive (company-begin-backend 'company-elisp))
     (prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
-                 (company-grab-lisp-symbol)))
+                 (company-elisp--prefix)))
     (candidates (company-elisp-candidates arg))
     (sorted company-elisp-show-locals-first)
-    (meta (company-elisp-doc arg))
+    (meta (company-elisp--doc arg))
     (doc-buffer (let ((symbol (intern arg)))
                   (save-window-excursion
                     (ignore-errors
diff --git a/company-tests.el b/company-tests.el
index d053965..011b67f 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -221,24 +221,24 @@
   (company-elisp-with-buffer
     "(foo ba|)"
     (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp-candidates-predicate "ba"))
+                  (company-elisp--candidates-predicate "ba"))
                 'boundp))
     (should (eq (let (company-elisp-detect-function-context)
-                  (company-elisp-candidates-predicate "ba"))
-                'company-elisp-predicate)))
+                  (company-elisp--candidates-predicate "ba"))
+                'company-elisp--predicate)))
   (company-elisp-with-buffer
     "(foo| )"
     (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp-candidates-predicate "foo"))
+                  (company-elisp--candidates-predicate "foo"))
                 'fboundp))
     (should (eq (let (company-elisp-detect-function-context)
-                  (company-elisp-candidates-predicate "foo"))
-                'company-elisp-predicate)))
+                  (company-elisp--candidates-predicate "foo"))
+                'company-elisp--predicate)))
   (company-elisp-with-buffer
     "(foo 'b|)"
     (should (eq (let ((company-elisp-detect-function-context t))
-                  (company-elisp-candidates-predicate "b"))
-                'company-elisp-predicate))))
+                  (company-elisp--candidates-predicate "b"))
+                'company-elisp--predicate))))
 
 ;; This one's also an integration test.
 (ert-deftest company-elisp-candidates-recognizes-binding-form ()
@@ -262,21 +262,21 @@
         (bar t)
         (baz t))
     (should (equal '("bar" "baz")
-                   (company-elisp-globals "ba" 'boundp)))))
+                   (company-elisp--globals "ba" 'boundp)))))
 
 (ert-deftest company-elisp-finds-functions ()
   (let ((obarray [when what whelp])
         (what t)
         (whelp t))
     (should (equal '("when")
-                   (company-elisp-globals "wh" 'fboundp)))))
+                   (company-elisp--globals "wh" 'fboundp)))))
 
 (ert-deftest company-elisp-finds-things ()
   (let ((obarray [when what whelp])
         (what t)
         (whelp t))
     (should (equal '("what" "whelp" "when")
-                   (sort (company-elisp-globals "wh" 'company-elisp-predicate)
+                   (sort (company-elisp--globals "wh" 
'company-elisp--predicate)
                          'string<)))))
 
 (ert-deftest company-elisp-locals-vars ()
@@ -286,7 +286,7 @@
          (lambda (boo baz)
            b|)))"
     (should (equal '("bar" "baz" "boo")
-                   (company-elisp-locals "b" nil)))))
+                   (company-elisp--locals "b" nil)))))
 
 (ert-deftest company-elisp-locals-single-var ()
   (company-elisp-with-buffer
@@ -294,7 +294,7 @@
        (dolist (item items)
          it|))"
     (should (equal '("itk" "item")
-                   (company-elisp-locals "it" nil)))))
+                   (company-elisp--locals "it" nil)))))
 
 (ert-deftest company-elisp-locals-funs ()
   (company-elisp-with-buffer
@@ -303,13 +303,13 @@
        (let ((fun 4))
          (f| )))"
     (should (equal '("fee" "foo")
-                   (sort (company-elisp-locals "f" t) 'string<)))))
+                   (sort (company-elisp--locals "f" t) 'string<)))))
 
 (ert-deftest company-elisp-locals-skips-current-varlist ()
   (company-elisp-with-buffer
     "(let ((foo 1)
            (f| )))"
-    (should (null (company-elisp-locals "f" nil)))))
+    (should (null (company-elisp--locals "f" nil)))))
 
 (ert-deftest company-elisp-show-locals-first ()
   (company-elisp-with-buffer

commit b446a994bb90e8a62cc7ff362c8e0421ef9c226f
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 22:34:35 2013 +0400

    company-elisp-fun-binding-regexp: Consider cl-flet*

diff --git a/company-elisp.el b/company-elisp.el
index 284775a..a27edae 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -72,7 +72,7 @@ first in the candidates list."
   "Regular expression matching head of a form with one variable binding.")
 
 (defvar company-elisp-fun-binding-regexp
-  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("flet" "labels")) "\\_>")
+  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("flet" "labels")) "\\*?\\_>")
   "Regular expression matching head of a function bindings form.")
 
 (defun company-elisp-locals (prefix functions-p)

commit ed75169bc3f458a25a192186c0d05bff8a54be36
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 22:31:38 2013 +0400

    company-pseudo-tooltip-frontend: Redraw less often when expanded upward

diff --git a/company.el b/company.el
index 4590683..35b0780 100644
--- a/company.el
+++ b/company.el
@@ -1797,7 +1797,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
                             args))
 
         (overlay-put ov 'company-column column)
-        (overlay-put ov 'company-height (abs height))))))
+        (overlay-put ov 'company-height height)))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (company--col-row pos)))
@@ -1810,7 +1810,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
         (height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (apply 'company--replacement-string
-                        (company--create-lines selection height)
+                        (company--create-lines selection (abs height))
                         (overlay-get company-pseudo-tooltip-overlay
                                      'company-replacement-args)))))
 

commit fa89135e030bdea584b9c3f87992e82f6b3fe1ab
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 17:58:36 2013 +0400

    company-elisp-show-locals-first: Add keywords to the defcustom

diff --git a/company-elisp.el b/company-elisp.el
index d878db0..284775a 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -39,7 +39,10 @@ Functions are offered for completion only after ' and \(."
 
 (defcustom company-elisp-show-locals-first t
   "If enabled, locally bound variables and functions are displayed
-first in the candidates list.")
+first in the candidates list."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" t)))
 
 (defun company-grab-lisp-symbol ()
   (let ((prefix (company-grab-symbol)))

commit 50293ad01f7ad9e1280a0b0845545516260f4505
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 07:12:31 2013 +0400

    company-elisp-var-binding-regexp: The three def macros also have cl versions

diff --git a/company-elisp.el b/company-elisp.el
index e4baca1..d878db0 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -59,8 +59,8 @@ first in the candidates list.")
 (defvar company-elisp-parse-depth 100)
 
 (defvar company-elisp-var-binding-regexp
-  (concat "\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
-                               "lambda" "lexical-let"))
+  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("let" "defun" "defmacro" "defsubst"
+                                           "lambda" "lexical-let"))
           "\\*?\\_>")
   "Regular expression matching head of a multiple variable bindings form.")
 

commit 4ff66327158ede1b470fc4616db1b68d9f561cd4
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 07:00:47 2013 +0400

    Change the summary in generated -pkg

diff --git a/Makefile b/Makefile
index d49adf3..de124c5 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ elpa: *.el
        mkdir -p "$$dir"; \
        cp `git ls-files '*.el' | xargs` company-$$version; \
        echo "(define-package \"company\" \"$$version\" \
-       \"extensible inline text completion mechanism\")" \
+       \"Modular in-buffer completion framework\")" \
        > "$$dir"/company-pkg.el; \
        tar cvf company-$$version.tar --mode 644 "$$dir"
 

commit 83cbc7d328415bdf7aedfa02ca3017d5cb16dd11
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 06:57:57 2013 +0400

    Release 0.6.5

diff --git a/NEWS.md b/NEWS.md
index f18fad5..6297652 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,6 @@
 # History of user-visible changes
 
-## Next
+## 2013-03-30 (0.6.5)
 
 * Fixed keybindings when running in a terminal.
 * `company-elisp-show-locals-first`: new customizable variable.
diff --git a/company-elisp.el b/company-elisp.el
index e685c2f..e4baca1 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,6 +1,6 @@
 ;;; company-elisp.el --- A company-mode completion back-end for 
emacs-lisp-mode -*- lexical-binding: t -*-
 
-;; Copyright (C) 2009, 2011-2012  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011-2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
diff --git a/company.el b/company.el
index 2e7a8f1..4590683 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.4
+;; Version: 0.6.5
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit 9218392f6e80c0f24979259721b23e9e75d61002
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 30 06:50:23 2013 +0400

    Fix #6
    
    Same problem and solution as in capitaomorte/yasnippet#296.

diff --git a/NEWS.md b/NEWS.md
index fed0e2a..f18fad5 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Fixed keybindings when running in a terminal.
 * `company-elisp-show-locals-first`: new customizable variable.
 * `company-elisp` shows more accurate and comprehensive candidates list.
 
diff --git a/company.el b/company.el
index ad0a649..2e7a8f1 100644
--- a/company.el
+++ b/company.el
@@ -490,7 +490,9 @@ The work-around consists of adding a newline.")
     (define-key keymap [up-mouse-1] 'ignore)
     (define-key keymap [up-mouse-3] 'ignore)
     (define-key keymap [return] 'company-complete-selection)
+    (define-key keymap (kbd "RET") 'company-complete-selection)
     (define-key keymap [tab] 'company-complete-common)
+    (define-key keymap (kbd "TAB") 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     (define-key keymap "\C-w" 'company-show-location)
     (define-key keymap "\C-s" 'company-search-candidates)

commit 3ac29fb27bc3809d04ce54f773dc5b3e3ccde78e
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 19:10:45 2013 +0400

    Fix NEWS entry

diff --git a/NEWS.md b/NEWS.md
index 374f69d..fed0e2a 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -3,7 +3,7 @@
 ## Next
 
 * `company-elisp-show-locals-first`: new customizable variable.
-* `company-eclim` shows more accurate and comprehensive candidates.
+* `company-elisp` shows more accurate and comprehensive candidates list.
 
 ## 2013-03-26 (0.6.4)
 

commit d260c2486281f630301925a1d6d2ebcc16bea1b8
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 14:31:19 2013 +0400

    company.el: lexical-binding: t

diff --git a/company.el b/company.el
index 5635026..ad0a649 100644
--- a/company.el
+++ b/company.el
@@ -1,4 +1,4 @@
-;;; company.el --- Modular in-buffer completion framework
+;;; company.el --- Modular in-buffer completion framework  -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2009-2013  Free Software Foundation, Inc.
 

commit 42e431dc7f4a22b476884139aa4d8b73aebdd25c
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 13:58:22 2013 +0400

    company-elisp-candidates-predicate: Blacklist specific special forms

diff --git a/company-elisp.el b/company-elisp.el
index eec64f4..e685c2f 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -135,8 +135,12 @@ first in the candidates list.")
                   (save-excursion
                     (ignore-errors
                       (up-list -2)
-                      (forward-char 1)
-                      (looking-at " *(")))))
+                      (and (save-excursion
+                             (forward-char 1)
+                             (looking-at "[ \t\n]*("))
+                           (prog1 (search-backward "(")
+                             (forward-char 1))
+                           (looking-at company-elisp-var-binding-regexp))))))
             'fboundp
           'boundp)
       'company-elisp-predicate)))
diff --git a/company-tests.el b/company-tests.el
index 4fcb83c..d053965 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -242,15 +242,19 @@
 
 ;; This one's also an integration test.
 (ert-deftest company-elisp-candidates-recognizes-binding-form ()
-  (company-elisp-with-buffer
-    "(let ((foo 7) (wh| )))"
-    (let ((obarray [when what whelp])
-          (what 1)
-          (whelp 2)
-          (wisp 3))
+  (let ((company-elisp-detect-function-context t)
+        (obarray [when what whelp])
+        (what 1)
+        (whelp 2)
+        (wisp 3))
+    (company-elisp-with-buffer
+      "(let ((foo 7) (wh| )))"
       (should (equal '("what" "whelp")
-                     (let ((company-elisp-detect-function-context t))
-                       (company-elisp-candidates "wh")))))))
+                     (company-elisp-candidates "wh"))))
+    (company-elisp-with-buffer
+      "(cond ((null nil) (wh| )))"
+      (should (equal '("when")
+                     (company-elisp-candidates "wh"))))))
 
 (ert-deftest company-elisp-finds-vars ()
   (let ((obarray [boo bar baz backquote])

commit 36108c9f82d401113c2b87c18576e9835bd44e1c
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 13:26:32 2013 +0400

    company-elisp-candidates: Deal with duplicates

diff --git a/company-elisp.el b/company-elisp.el
index c862edb..eec64f4 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,4 +1,4 @@
-;;; company-elisp.el --- A company-mode completion back-end for emacs-lisp-mode
+;;; company-elisp.el --- A company-mode completion back-end for 
emacs-lisp-mode -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2009, 2011-2012  Free Software Foundation, Inc.
 
@@ -113,7 +113,10 @@ first in the candidates list.")
 (defun company-elisp-candidates (prefix)
   (let* ((predicate (company-elisp-candidates-predicate prefix))
          (locals (company-elisp-locals prefix (eq predicate 'fboundp)))
-         (globals (company-elisp-globals prefix predicate)))
+         (globals (company-elisp-globals prefix predicate))
+         (locals (loop for local in locals
+                       when (not (member local globals))
+                       collect local)))
     (if company-elisp-show-locals-first
         (append (sort locals 'string<)
                 (sort globals 'string<))
diff --git a/company-tests.el b/company-tests.el
index 0ca2e11..4fcb83c 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -320,3 +320,11 @@
         (should (eq t (company-elisp 'sorted)))
         (should (equal '("flee" "floo" "flop" "float-pi")
                        (company-elisp-candidates "fl")))))))
+
+(ert-deftest company-elisp-candidates-no-duplicates ()
+  (company-elisp-with-buffer
+    "(let ((float-pi 4))
+       f|)"
+    (let ((obarray [float-pi])
+          (company-elisp-show-locals-first t))
+      (should (equal '("float-pi") (company-elisp-candidates "f"))))))

commit fb0e4cf536171c8faedd1df612563a327bb7baae
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 12:36:13 2013 +0400

    company-elisp-show-locals-first: New defcustom

diff --git a/NEWS.md b/NEWS.md
index 2aced04..374f69d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,10 @@
 # History of user-visible changes
 
+## Next
+
+* `company-elisp-show-locals-first`: new customizable variable.
+* `company-eclim` shows more accurate and comprehensive candidates.
+
 ## 2013-03-26 (0.6.4)
 
 * `company-eclim` shows valid completions after an opening paren.
diff --git a/company-elisp.el b/company-elisp.el
index 52126bd..c862edb 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -37,6 +37,10 @@ Functions are offered for completion only after ' and \(."
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
+(defcustom company-elisp-show-locals-first t
+  "If enabled, locally bound variables and functions are displayed
+first in the candidates list.")
+
 (defun company-grab-lisp-symbol ()
   (let ((prefix (company-grab-symbol)))
     (if prefix
@@ -107,9 +111,13 @@ Functions are offered for completion only after ' and \(."
     res))
 
 (defun company-elisp-candidates (prefix)
-  (let ((predicate (company-elisp-candidates-predicate prefix)))
-    (append (company-elisp-locals prefix (eq predicate 'fboundp))
-            (company-elisp-globals prefix predicate))))
+  (let* ((predicate (company-elisp-candidates-predicate prefix))
+         (locals (company-elisp-locals prefix (eq predicate 'fboundp)))
+         (globals (company-elisp-globals prefix predicate)))
+    (if company-elisp-show-locals-first
+        (append (sort locals 'string<)
+                (sort globals 'string<))
+      (append locals globals))))
 
 (defun company-elisp-globals (prefix predicate)
   (all-completions prefix obarray predicate))
@@ -148,6 +156,7 @@ Functions are offered for completion only after ' and \(."
     (prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                  (company-grab-lisp-symbol)))
     (candidates (company-elisp-candidates arg))
+    (sorted company-elisp-show-locals-first)
     (meta (company-elisp-doc arg))
     (doc-buffer (let ((symbol (intern arg)))
                   (save-window-excursion
diff --git a/company-tests.el b/company-tests.el
index c9e52cb..0ca2e11 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -306,3 +306,17 @@
     "(let ((foo 1)
            (f| )))"
     (should (null (company-elisp-locals "f" nil)))))
+
+(ert-deftest company-elisp-show-locals-first ()
+  (company-elisp-with-buffer
+    "(let ((floo 1)
+           (flop 2)
+           (flee 3))
+       fl|)"
+    (let ((obarray [float-pi]))
+      (let (company-elisp-show-locals-first)
+        (should (eq nil (company-elisp 'sorted))))
+      (let ((company-elisp-show-locals-first t))
+        (should (eq t (company-elisp 'sorted)))
+        (should (equal '("flee" "floo" "flop" "float-pi")
+                       (company-elisp-candidates "fl")))))))

commit bcae310be39553776055e0d8bc6289555f6ed736
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 12:08:43 2013 +0400

    company-elisp-locals: Skip current varlist

diff --git a/company-elisp.el b/company-elisp.el
index 42e3fef..52126bd 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -80,30 +80,29 @@ Functions are offered for completion only after ' and \(."
             (save-excursion
               (when (eq (char-after) ?\()
                 (forward-char 1)
-                (skip-chars-forward " \t\n")
-                (cond
-                 ((looking-at (if functions-p
-                                  company-elisp-fun-binding-regexp
-                                company-elisp-var-binding-regexp))
-                  (down-list 1)
-                  (condition-case nil
-                      (dotimes (i company-elisp-parse-limit)
-                        (save-excursion
-                          (when (looking-at "[ \t\n]*(")
-                            (down-list 1))
-                          (and (looking-at regexp)
-                               ;; Don't add incomplete text as candidate.
-                               (not (eq (match-end 0) pos))
-                               (pushnew (match-string-no-properties 1) res)))
-                        (forward-sexp))
-                    (scan-error nil)))
-                 ((unless functions-p
-                    (looking-at company-elisp-var-binding-regexp-1))
-                  (down-list 1)
-                  (and (looking-at regexp)
-                       ;; Don't add incomplete text as candidate.
-                       (not (eq (match-end 0) pos))
-                       (pushnew (match-string-no-properties 1) res))))))))
+                (when (ignore-errors
+                        (save-excursion (forward-list)
+                                        (<= (point) pos)))
+                  (skip-chars-forward " \t\n")
+                  (cond
+                   ((looking-at (if functions-p
+                                    company-elisp-fun-binding-regexp
+                                  company-elisp-var-binding-regexp))
+                    (down-list 1)
+                    (condition-case nil
+                        (dotimes (i company-elisp-parse-limit)
+                          (save-excursion
+                            (when (looking-at "[ \t\n]*(")
+                              (down-list 1))
+                            (when (looking-at regexp)
+                              (pushnew (match-string-no-properties 1) res)))
+                          (forward-sexp))
+                      (scan-error nil)))
+                   ((unless functions-p
+                      (looking-at company-elisp-var-binding-regexp-1))
+                    (down-list 1)
+                    (when (looking-at regexp)
+                      (pushnew (match-string-no-properties 1) res)))))))))
       (scan-error nil))
     res))
 
diff --git a/company-tests.el b/company-tests.el
index 77ccee7..c9e52cb 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -300,3 +300,9 @@
          (f| )))"
     (should (equal '("fee" "foo")
                    (sort (company-elisp-locals "f" t) 'string<)))))
+
+(ert-deftest company-elisp-locals-skips-current-varlist ()
+  (company-elisp-with-buffer
+    "(let ((foo 1)
+           (f| )))"
+    (should (null (company-elisp-locals "f" nil)))))

commit d0963a5db772b31f77f8a34700cfa401906302fd
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 11:48:03 2013 +0400

    company-elisp-locals: Differentiate local function and variable bindings

diff --git a/company-elisp.el b/company-elisp.el
index b6e5961..42e3fef 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -54,51 +54,63 @@ Functions are offered for completion only after ' and \(."
 (defvar company-elisp-parse-limit 30)
 (defvar company-elisp-parse-depth 100)
 
-(defvar company-elisp-binding-regexp
-  (concat "([ \t\n]*\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
-                                        "lambda" "lexical-let" "flet" 
"labels"))
-          "\\*?")
-  "Regular expression matching sexps containing variable bindings.")
+(defvar company-elisp-var-binding-regexp
+  (concat "\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
+                               "lambda" "lexical-let"))
+          "\\*?\\_>")
+  "Regular expression matching head of a multiple variable bindings form.")
 
-(defvar company-elisp-binding-regexp-1
-  (concat "([ \t\n]*\\_<" (regexp-opt '("dolist" "dotimes")))
-  "Regular expression matching sexps containing one variable binding.")
+(defvar company-elisp-var-binding-regexp-1
+  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("dolist" "dotimes")) "\\_>")
+  "Regular expression matching head of a form with one variable binding.")
 
-(defun company-elisp-locals (prefix)
+(defvar company-elisp-fun-binding-regexp
+  (concat "\\_<\\(?:cl-\\)?" (regexp-opt '("flet" "labels")) "\\_>")
+  "Regular expression matching head of a function bindings form.")
+
+(defun company-elisp-locals (prefix functions-p)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
         (pos (point))
         res)
-    (ignore-errors
-      (save-excursion
-        (dotimes (i company-elisp-parse-depth)
-          (up-list -1)
-          (save-excursion
-            (cond
-             ((looking-at company-elisp-binding-regexp)
-              (down-list 2)
-              (ignore-errors
-                (dotimes (i company-elisp-parse-limit)
-                  (save-excursion
-                    (when (looking-at "[ \t\n]*(")
-                      (down-list 1))
-                    (and (looking-at regexp)
-                         ;; Don't add incomplete text as candidate.
-                         (not (eq (match-end 0) pos))
-                         (push (match-string-no-properties 1) res)))
-                  (forward-sexp))))
-             ((looking-at company-elisp-binding-regexp-1)
-              (down-list 2)
-              (and (looking-at regexp)
-                   ;; Don't add incomplete text as candidate.
-                   (not (eq (match-end 0) pos))
-                   (pushnew (match-string-no-properties 1) res))))))))
+    (condition-case nil
+        (save-excursion
+          (dotimes (i company-elisp-parse-depth)
+            (up-list -1)
+            (save-excursion
+              (when (eq (char-after) ?\()
+                (forward-char 1)
+                (skip-chars-forward " \t\n")
+                (cond
+                 ((looking-at (if functions-p
+                                  company-elisp-fun-binding-regexp
+                                company-elisp-var-binding-regexp))
+                  (down-list 1)
+                  (condition-case nil
+                      (dotimes (i company-elisp-parse-limit)
+                        (save-excursion
+                          (when (looking-at "[ \t\n]*(")
+                            (down-list 1))
+                          (and (looking-at regexp)
+                               ;; Don't add incomplete text as candidate.
+                               (not (eq (match-end 0) pos))
+                               (pushnew (match-string-no-properties 1) res)))
+                        (forward-sexp))
+                    (scan-error nil)))
+                 ((unless functions-p
+                    (looking-at company-elisp-var-binding-regexp-1))
+                  (down-list 1)
+                  (and (looking-at regexp)
+                       ;; Don't add incomplete text as candidate.
+                       (not (eq (match-end 0) pos))
+                       (pushnew (match-string-no-properties 1) res))))))))
+      (scan-error nil))
     res))
 
 (defun company-elisp-candidates (prefix)
-  (append (company-elisp-locals prefix)
-          (company-elisp-globals prefix
-                                 (company-elisp-candidates-predicate prefix))))
+  (let ((predicate (company-elisp-candidates-predicate prefix)))
+    (append (company-elisp-locals prefix (eq predicate 'fboundp))
+            (company-elisp-globals prefix predicate))))
 
 (defun company-elisp-globals (prefix predicate)
   (all-completions prefix obarray predicate))
diff --git a/company-tests.el b/company-tests.el
index 30d898b..77ccee7 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -240,7 +240,7 @@
                   (company-elisp-candidates-predicate "b"))
                 'company-elisp-predicate))))
 
-;; Mix it up with an integration test.
+;; This one's also an integration test.
 (ert-deftest company-elisp-candidates-recognizes-binding-form ()
   (company-elisp-with-buffer
     "(let ((foo 7) (wh| )))"
@@ -274,3 +274,29 @@
     (should (equal '("what" "whelp" "when")
                    (sort (company-elisp-globals "wh" 'company-elisp-predicate)
                          'string<)))))
+
+(ert-deftest company-elisp-locals-vars ()
+  (company-elisp-with-buffer
+    "(let ((foo 5) (bar 6))
+       (cl-labels ((borg ()))
+         (lambda (boo baz)
+           b|)))"
+    (should (equal '("bar" "baz" "boo")
+                   (company-elisp-locals "b" nil)))))
+
+(ert-deftest company-elisp-locals-single-var ()
+  (company-elisp-with-buffer
+    "(dotimes (itk 100)
+       (dolist (item items)
+         it|))"
+    (should (equal '("itk" "item")
+                   (company-elisp-locals "it" nil)))))
+
+(ert-deftest company-elisp-locals-funs ()
+  (company-elisp-with-buffer
+    "(cl-labels ((foo ())
+                 (fee ()))
+       (let ((fun 4))
+         (f| )))"
+    (should (equal '("fee" "foo")
+                   (sort (company-elisp-locals "f" t) 'string<)))))

commit 8427b8f1edd77234349930f440b2f03bf519221b
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 29 09:09:41 2013 +0400

    company-elisp-candidates: Recognize when inside varlist
    
    * Extract -candidates-predicate and -globals.
    * Add tests.
    * Rename -parse-local to -locals, accept just one argument.

diff --git a/company-elisp.el b/company-elisp.el
index 986cd3d..b6e5961 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -64,10 +64,11 @@ Functions are offered for completion only after ' and \(."
   (concat "([ \t\n]*\\_<" (regexp-opt '("dolist" "dotimes")))
   "Regular expression matching sexps containing one variable binding.")
 
-(defun company-elisp-parse-local (prefix vars)
+(defun company-elisp-locals (prefix)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
-        (pos (point)))
+        (pos (point))
+        res)
     (ignore-errors
       (save-excursion
         (dotimes (i company-elisp-parse-depth)
@@ -84,27 +85,39 @@ Functions are offered for completion only after ' and \(."
                     (and (looking-at regexp)
                          ;; Don't add incomplete text as candidate.
                          (not (eq (match-end 0) pos))
-                         (add-to-list 'vars (match-string-no-properties 1))))
+                         (push (match-string-no-properties 1) res)))
                   (forward-sexp))))
              ((looking-at company-elisp-binding-regexp-1)
               (down-list 2)
               (and (looking-at regexp)
                    ;; Don't add incomplete text as candidate.
                    (not (eq (match-end 0) pos))
-                   (add-to-list 'vars (match-string-no-properties 1)))))))))
-    vars))
+                   (pushnew (match-string-no-properties 1) res))))))))
+    res))
 
 (defun company-elisp-candidates (prefix)
+  (append (company-elisp-locals prefix)
+          (company-elisp-globals prefix
+                                 (company-elisp-candidates-predicate prefix))))
+
+(defun company-elisp-globals (prefix predicate)
+  (all-completions prefix obarray predicate))
+
+(defun company-elisp-candidates-predicate (prefix)
   (let* ((completion-ignore-case nil)
-         (before (char-before (- (point) (length prefix))))
-         (predicate (if (and company-elisp-detect-function-context
-                             (not (eq before ?')))
-                        (if (eq before ?\()
-                            'fboundp
-                          'boundp)
-                      'company-elisp-predicate))
-         (candidates (all-completions prefix obarray predicate)))
-    (company-elisp-parse-local prefix candidates)))
+         (before (char-before (- (point) (length prefix)))))
+    (if (and company-elisp-detect-function-context
+             (not (eq before ?')))
+        (if (and (eq before ?\()
+                 (not
+                  (save-excursion
+                    (ignore-errors
+                      (up-list -2)
+                      (forward-char 1)
+                      (looking-at " *(")))))
+            'fboundp
+          'boundp)
+      'company-elisp-predicate)))
 
 (defun company-elisp-doc (symbol)
   (let* ((symbol (intern symbol))
diff --git a/company-tests.el b/company-tests.el
index 5d08c94..30d898b 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -208,3 +208,69 @@
     (apply command args)
     (let ((this-command command))
       (run-hooks 'post-command-hook))))
+
+(defmacro company-elisp-with-buffer (contents &rest body)
+  (declare (indent 0))
+  `(with-temp-buffer
+     (insert ,contents)
+     (re-search-backward "|")
+     (replace-match "")
+     ,@body))
+
+(ert-deftest company-elisp-candidates-predicate ()
+  (company-elisp-with-buffer
+    "(foo ba|)"
+    (should (eq (let ((company-elisp-detect-function-context t))
+                  (company-elisp-candidates-predicate "ba"))
+                'boundp))
+    (should (eq (let (company-elisp-detect-function-context)
+                  (company-elisp-candidates-predicate "ba"))
+                'company-elisp-predicate)))
+  (company-elisp-with-buffer
+    "(foo| )"
+    (should (eq (let ((company-elisp-detect-function-context t))
+                  (company-elisp-candidates-predicate "foo"))
+                'fboundp))
+    (should (eq (let (company-elisp-detect-function-context)
+                  (company-elisp-candidates-predicate "foo"))
+                'company-elisp-predicate)))
+  (company-elisp-with-buffer
+    "(foo 'b|)"
+    (should (eq (let ((company-elisp-detect-function-context t))
+                  (company-elisp-candidates-predicate "b"))
+                'company-elisp-predicate))))
+
+;; Mix it up with an integration test.
+(ert-deftest company-elisp-candidates-recognizes-binding-form ()
+  (company-elisp-with-buffer
+    "(let ((foo 7) (wh| )))"
+    (let ((obarray [when what whelp])
+          (what 1)
+          (whelp 2)
+          (wisp 3))
+      (should (equal '("what" "whelp")
+                     (let ((company-elisp-detect-function-context t))
+                       (company-elisp-candidates "wh")))))))
+
+(ert-deftest company-elisp-finds-vars ()
+  (let ((obarray [boo bar baz backquote])
+        (boo t)
+        (bar t)
+        (baz t))
+    (should (equal '("bar" "baz")
+                   (company-elisp-globals "ba" 'boundp)))))
+
+(ert-deftest company-elisp-finds-functions ()
+  (let ((obarray [when what whelp])
+        (what t)
+        (whelp t))
+    (should (equal '("when")
+                   (company-elisp-globals "wh" 'fboundp)))))
+
+(ert-deftest company-elisp-finds-things ()
+  (let ((obarray [when what whelp])
+        (what t)
+        (whelp t))
+    (should (equal '("what" "whelp" "when")
+                   (sort (company-elisp-globals "wh" 'company-elisp-predicate)
+                         'string<)))))

commit f5e957045bb1f45f2aef8fd2ff43828e8a19891f
Author: Leo Liu <address@hidden>
Date:   Thu Mar 28 10:48:43 2013 +0800

    Comment fix

diff --git a/ggtags.el b/ggtags.el
index f2c6da2..4d8671b 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6.2
+;; Version: 0.6.3
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -23,8 +23,30 @@
 
 ;;; Commentary:
 
-;; Use GNU Global source code tagging system in Emacs.
-;; http://www.gnu.org/software/global
+;; A package to integrate GNU Global source code tagging system
+;; (http://www.gnu.org/software/global) with Emacs.
+;;
+;; Usage:
+;;
+;; Type `M-x ggtags-mode' to enable the minor mode, or as usual enable
+;; it in your desired major mode hooks. When the mode is on the symbol
+;; at point is underlined if it is a valid (definition) tag.
+;;
+;; `M-.' finds definition or references according to the context at
+;; point, i.e. if point is at a definition tag find references and
+;; vice versa. `C-u M-.' is verbose and will ask you the name - with
+;; completion - and the type of tag to search.
+;;
+;; If multiple matches are found, navigation mode is entered. In this
+;; mode, `M-n' and `M-p' moves to next and previous match, `M-}' and
+;; `M-{' to next and previous file respectively. `M-o' toggles between
+;; full and abbreviated displays of file names in the auxiliary popup
+;; window. When you locate the right match, press RET to finish which
+;; hides the auxiliary window and exits navigation mode. You can
+;; resume the search using `M-,'. To abort the search press `M-*'.
+;;
+;; Normally after a few searches a dozen buffers are created visiting
+;; files tracked by GNU Global. `C-c M-k' helps clean them up.
 
 ;;; Code:
 

commit e7dc3a7617d84b0f6955d0921a9143bbff2ba4ab
Author: Leo Liu <address@hidden>
Date:   Tue Mar 26 14:06:53 2013 +0800

    Fix #4: handle buffers not visiting files more gracefully

diff --git a/ggtags.el b/ggtags.el
index bc31168..f2c6da2 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -217,10 +217,10 @@ When called with prefix, ask the name and kind of tag."
          (lambda (w) (split-window (frame-root-window w))))
         (default-directory (ggtags-root-directory)))
     (compilation-start
-     (if verbose
+     (if (or verbose (not buffer-file-name))
          (format "global %s %s \"%s\""
                  ggtags-global-options
-                 (if (y-or-n-p "Kind (y for definition n for reference)? ")
+                 (if (y-or-n-p "Find definition (n for reference)? ")
                      "" "-r")
                  name)
        (format "global %s --from-here=%d:%s \"%s\""

commit 8ec2c2db395f14ab194cd585150b8cbc6dadf42f
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 26 08:18:00 2013 +0400

    company-eclim: Get valid completions just after an opening paren

diff --git a/NEWS.md b/NEWS.md
index ebb0dc6..2aced04 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## 2013-03-26 (0.6.4)
 
+* `company-eclim` shows valid completions after an opening paren.
 * Expanded template does not get removed until the point leaves it.  After your
   input the last argument in a method call expanded by `company-eclim`, you can
   press `<tab>` once more, to jump after the closing paren.  No other bundled
diff --git a/company-eclim.el b/company-eclim.el
index b0444c0..b9ac242 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -120,7 +120,8 @@ eclim can only complete correctly when the buffer has been 
saved."
                               (company-eclim--call-process
                                "java_complete" "-p" 
(company-eclim--project-name)
                                "-f" project-file
-                               "-o" (number-to-string (1- (point)))
+                               "-o" (number-to-string
+                                     (company-eclim--search-point prefix))
                                "-e" "utf-8"
                                "-l" "standard"))))
       (let* ((meta (cdr (assoc 'info item)))
@@ -131,6 +132,11 @@ eclim can only complete correctly when the buffer has been 
saved."
   (let ((completion-ignore-case nil))
     (all-completions prefix company-eclim--doc)))
 
+(defun company-eclim--search-point (prefix)
+  (if (or (plusp (length prefix)) (eq (char-before) ?.))
+      (1- (point))
+    (point)))
+
 (defun company-eclim--meta (candidate)
   (gethash candidate company-eclim--doc))
 

commit 35e38bb102b04fa59f64e9bfe7b693d2082d748a
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 26 08:04:40 2013 +0400

    company-template: Hold off on removing the template until point leaves

diff --git a/NEWS.md b/NEWS.md
index 6de6d11..ebb0dc6 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,12 @@
 # History of user-visible changes
 
+## 2013-03-26 (0.6.4)
+
+* Expanded template does not get removed until the point leaves it.  After your
+  input the last argument in a method call expanded by `company-eclim`, you can
+  press `<tab>` once more, to jump after the closing paren.  No other bundled
+  back-ends are affected.
+
 ## 2013-03-25 (0.6.3)
 
 * New tooltip face colors used on themes with light background.
diff --git a/company-template.el b/company-template.el
index 05389ac..ffceda1 100644
--- a/company-template.el
+++ b/company-template.el
@@ -39,7 +39,9 @@
 (defun company-template-templates-at (pos)
   (let (os)
     (dolist (o (overlays-at pos))
-      (when (overlay-get o 'company-template-fields)
+      ;; FIXME: Always return the whole list of templates?
+      ;; We remove templates not at point after every command.
+      (when (memq o company-template--buffer-templates)
         (push o os)))
     os))
 
@@ -121,11 +123,9 @@
 
 (defun company-template-clean-up (&optional pos)
   "Clean up all templates that don't contain POS."
-  (unless pos (setq pos (point)))
-  (let ((local-ovs (overlays-in (- pos 2) pos)))
+  (let ((local-ovs (overlays-at (or pos (point)))))
     (dolist (templ company-template--buffer-templates)
-      (unless (and (memq templ local-ovs)
-                   (overlay-get templ 'company-template-fields))
+      (unless (memq templ local-ovs)
         (company-template-remove-template templ)))))
 
 ;; hooks 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/company-tests.el b/company-tests.el
index 55675c9..5d08c94 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -73,8 +73,7 @@
                      (prefix "a")
                      (candidates '("a" "ab" "ac")))))))
       (let (this-command)
-        (company-complete))
-      (company-post-command)
+        (company-call 'complete))
       (should (eq 3 company-candidates-length)))))
 
 (ert-deftest company-require-match-explicit ()
@@ -91,8 +90,7 @@
       (let (this-command)
         (company-complete))
       (let ((last-command-event ?e))
-        (self-insert-command 1))
-      (company-post-command)
+        (company-call 'self-insert-command 1))
       (should (eq 2 company-candidates-length))
       (should (eq 3 (point))))))
 
@@ -110,8 +108,7 @@
       (company-idle-begin (current-buffer) (selected-window)
                           (buffer-chars-modified-tick) (point))
       (let ((last-command-event ?e))
-        (self-insert-command 1))
-      (company-post-command)
+        (company-call 'self-insert-command 1))
       (should (eq nil company-candidates-length))
       (should (eq 4 (point))))))
 
@@ -130,8 +127,7 @@
       (let (this-command)
         (company-complete))
       (let ((last-command-event ? ))
-        (self-insert-command 1))
-      (company-post-command)
+        (company-call 'self-insert-command 1))
       (should (string= "abcd " (buffer-string))))))
 
 (ert-deftest company-no-auto-complete-when-idle ()
@@ -149,8 +145,7 @@
       (company-idle-begin (current-buffer) (selected-window)
                           (buffer-chars-modified-tick) (point))
       (let ((last-command-event ? ))
-        (self-insert-command 1))
-      (company-post-command)
+        (company-call 'self-insert-command 1))
       (should (string= "ab " (buffer-string))))))
 
 (ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
@@ -165,8 +160,51 @@
              (list (lambda (c &optional arg)
                      (case c (prefix "") (candidates '("a" "b" "c")))))))
         (let (this-command)
-          (company-complete))
-        (company-post-command)
-        (open-line 1)
-        (company-post-command)
+          (company-call 'complete))
+        (company-call 'open-line 1)
         (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
+
+(ert-deftest company-template-removed-after-the-last-jump ()
+  (with-temp-buffer
+    (insert "{ }")
+    (goto-char 2)
+    (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
+      (save-excursion
+        (dotimes (i 2)
+          (insert " ")
+          (company-template-add-field tpl (point) "foo")
+          (forward-char 3)))
+      (company-call 'template-forward-field)
+      (should (= 3 (point)))
+      (company-call 'template-forward-field)
+      (should (= 7 (point)))
+      (company-call 'template-forward-field)
+      (should (= 11 (point)))
+      (should (zerop (length (overlay-get tpl 'company-template-fields))))
+      (should (null (overlay-buffer tpl))))))
+
+(ert-deftest company-template-removed-after-input-and-jump ()
+  (with-temp-buffer
+    (insert "{ }")
+    (goto-char 2)
+    (let ((tpl (company-template-declare-template (point) (1- (point-max)))))
+      (save-excursion
+        (insert " ")
+        (company-template-add-field tpl (point) "bar"))
+      (company-call 'template-move-to-first tpl)
+      (should (= 3 (point)))
+      (dolist (c (string-to-list "tee"))
+        (let ((last-command-event c))
+          (company-call 'self-insert-command 1)))
+      (should (string= "{ tee }" (buffer-string)))
+      (should (overlay-buffer tpl))
+      (company-call 'template-forward-field)
+      (should (= 7 (point)))
+      (should (null (overlay-buffer tpl))))))
+
+(defun company-call (name &rest args)
+  (let* ((maybe (intern (format "company-%s" name)))
+         (command (if (fboundp maybe) maybe name)))
+    (apply command args)
+    (let ((this-command command))
+      (run-hooks 'post-command-hook))))
diff --git a/company.el b/company.el
index 5680735..5635026 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.3
+;; Version: 0.6.4
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit 99efa0e85d46f3dff2185d5439704aa809403084
Author: Leo Liu <address@hidden>
Date:   Mon Mar 25 20:45:54 2013 +0800

    Give higher priority to ggtags-navigation-mode
    
    or modes such as view-mode may shadow its key bindings.

diff --git a/ggtags.el b/ggtags.el
index 9992eaf..bc31168 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -515,5 +515,14 @@ When called with prefix, ask the name and kind of tag."
       (setq he-expand-list (cdr he-expand-list))
       t)))
 
+;;; Finish up
+
+;; Higher priority for `ggtags-navigation-mode' to avoid being
+;; hijacked by modes such as `view-mode'.
+(defvar ggtags-mode-map-alist
+  `((ggtags-navigation-mode . ,ggtags-navigation-mode-map)))
+
+(add-to-list 'emulation-mode-map-alists 'ggtags-mode-map-alist)
+
 (provide 'ggtags)
 ;;; ggtags.el ends here

commit cdebad70a0873c0f9eca7b572aebe8b9a6f203e2
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 13:59:31 2013 +0400

    Add new tooltip face colors

diff --git a/NEWS.md b/NEWS.md
index cc21755..6de6d11 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,7 +1,8 @@
 # History of user-visible changes
 
-## Next
+## 2013-03-25 (0.6.3)
 
+* New tooltip face colors used on themes with light background.
 * Pseudo-tooltip stays up-to-date when text is inserted after the point.
 * Fixed `company-require-match` mechanics.
 
diff --git a/company.el b/company.el
index 078400f..5680735 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.2
+;; Version: 0.6.3
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
@@ -86,14 +86,20 @@
   :group 'matching)
 
 (defface company-tooltip
-  '((t :background "yellow"
-       :foreground "black"))
+  '((default :foreground "black")
+    (((class color) (min-colors 88) (background light))
+     (:background "cornsilk"))
+    (((class color) (min-colors 88) (background dark))
+     (:background "yellow")))
   "Face used for the tool tip."
   :group 'company)
 
 (defface company-tooltip-selection
   '((default :inherit company-tooltip)
-    (((class color) (min-colors 88)) (:background "orange1"))
+    (((class color) (min-colors 88) (background light))
+     (:background "light blue"))
+    (((class color) (min-colors 88) (background dark))
+     (:background "orange1"))
     (t (:background "green")))
   "Face used for the selection in the tool tip."
   :group 'company)
@@ -104,14 +110,20 @@
   :group 'company)
 
 (defface company-tooltip-common
-  '((t :inherit company-tooltip
-       :foreground "red"))
+  '((default :inherit company-tooltip)
+    (((background light))
+     :foreground "darkred")
+    (((background dark))
+     :foreground "red"))
   "Face used for the common completion in the tool tip."
   :group 'company)
 
 (defface company-tooltip-common-selection
-  '((t :inherit company-tooltip-selection
-       :foreground "red"))
+  '((default :inherit company-tooltip-selection)
+    (((background light))
+     :foreground "darkred")
+    (((background dark))
+     :foreground "red"))
   "Face used for the selected common completion in the tool tip."
   :group 'company)
 

commit 3a0a1eebe2be8f71c9541ed11a8bd79343cedb7e
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 11:39:46 2013 +0400

    company-pseudo-tooltip-frontend: Redraw when diplaced

diff --git a/NEWS.md b/NEWS.md
index fc1ffc2..cc21755 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Pseudo-tooltip stays up-to-date when text is inserted after the point.
 * Fixed `company-require-match` mechanics.
 
 ## 2013-03-24 (0.6.2)
diff --git a/company-tests.el b/company-tests.el
index ee477e7..55675c9 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -152,3 +152,21 @@
         (self-insert-command 1))
       (company-post-command)
       (should (string= "ab " (buffer-string))))))
+
+(ert-deftest company-pseudo-tooltip-does-not-get-displaced ()
+  (with-temp-buffer
+    (save-window-excursion
+      (set-window-buffer nil (current-buffer))
+      (save-excursion (insert " ff"))
+      (company-mode)
+      (let ((company-frontends '(company-pseudo-tooltip-frontend))
+            (company-begin-commands '(self-insert-command))
+            (company-backends
+             (list (lambda (c &optional arg)
+                     (case c (prefix "") (candidates '("a" "b" "c")))))))
+        (let (this-command)
+          (company-complete))
+        (company-post-command)
+        (open-line 1)
+        (company-post-command)
+        (should (eq 2 (overlay-start company-pseudo-tooltip-overlay)))))))
diff --git a/company.el b/company.el
index 0d33ad3..078400f 100644
--- a/company.el
+++ b/company.el
@@ -1817,6 +1817,10 @@ Returns a negative number if the tooltip should be 
displayed above point."
                  (overlay-get company-pseudo-tooltip-overlay 'company-before))
     (overlay-put company-pseudo-tooltip-overlay 'window (selected-window))))
 
+(defun company-pseudo-tooltip-guard ()
+  (buffer-substring-no-properties
+   (point) (overlay-start company-pseudo-tooltip-overlay)))
+
 (defun company-pseudo-tooltip-frontend (command)
   "A `company-mode' front-end similar to a tool-tip but based on overlays."
   (case command
@@ -1828,10 +1832,15 @@ Returns a negative number if the tooltip should be 
displayed above point."
                          0))
            (new-height (company--pseudo-tooltip-height)))
        (unless (and (>= (* old-height new-height) 0)
-                    (>= (abs old-height) (abs new-height)))
+                    (>= (abs old-height) (abs new-height))
+                    (equal (company-pseudo-tooltip-guard)
+                           (overlay-get company-pseudo-tooltip-overlay
+                                        'company-guard)))
          ;; Redraw needed.
          (company-pseudo-tooltip-show-at-point (- (point)
-                                                  (length company-prefix)))))
+                                                  (length company-prefix)))
+         (overlay-put company-pseudo-tooltip-overlay
+                      'company-guard (company-pseudo-tooltip-guard))))
      (company-pseudo-tooltip-unhide))
     (hide (company-pseudo-tooltip-hide)
           (setq company-tooltip-offset 0))

commit 177478df812600d37d41b7f14443c97a42f9ddd0
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 06:43:31 2013 +0400

    company-completion-finished-hook: mention post-completion command

diff --git a/company.el b/company.el
index 674fc96..0d33ad3 100644
--- a/company.el
+++ b/company.el
@@ -363,7 +363,10 @@ aborted manually."
 
 (defcustom company-completion-finished-hook nil
   "Hook run when company successfully completes.
-The hook is called with the selected candidate as an argument."
+The hook is called with the selected candidate as an argument.
+
+If you indend to use it to post-process candidates from a specific back-end,
+consider using the `post-completion' command instead."
   :group 'company
   :type 'hook)
 
@@ -405,7 +408,7 @@ completion.  If it is a list of syntax description 
characters (see
 This can also be a function, which is called with the new input and should
 return non-nil if company should auto-complete.
 
-A character that is part of a valid candidate never starts auto-completion."
+A character that is part of a valid candidate never triggers auto-completion."
   :group 'company
   :type '(choice (string :tag "Characters")
                  (set :tag "Syntax"

commit 1c07663062f3456c64f6d0f2554e505b7815c921
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 03:10:16 2013 +0400

    company-eclim: Rewrite commentary

diff --git a/company-eclim.el b/company-eclim.el
index e6e2fb6..b0444c0 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -21,12 +21,12 @@
 
 ;;; Commentary:
 ;;
-;; Eclim version 1.7.13 or newer (?) is required.
+;; Using `emacs-eclim' together with (or instead of) this back-end is
+;; recommended, as it allows you to use other Eclim features.
 ;;
-;; This completion backend is pretty barebone.
-;;
-;; `emacs-eclim' provides an alternative backend, and it also allows you to
-;; actually control Eclim from Emacs.
+;; The alternative back-end provided by `emacs-eclim' uses `yasnippet'
+;; instead of `company-template' to expand function calls, and it supports
+;; some languages other than Java.
 
 ;;; Code:
 
@@ -148,8 +148,10 @@ eclim can only complete correctly when the buffer has been 
saved."
     (company-template-move-to-first templ)))
 
 (defun company-eclim (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for eclim.
-eclim provides access to Eclipse Java IDE features for other editors.
+  "A `company-mode' completion back-end for Eclim.
+Eclim provides access to Eclipse Java IDE features for other editors.
+
+Eclim version 1.7.13 or newer (?) is required.
 
 Completions only work correctly when the buffer has been saved.
 `company-eclim-auto-save' determines whether to do this automatically."

commit 5a18e987dd87b33d1e8c8250d08f6580b1eb1737
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 02:53:49 2013 +0400

    Add two tests for company-auto-complete

diff --git a/company-tests.el b/company-tests.el
index fd89b58..ee477e7 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -96,7 +96,7 @@
       (should (eq 2 company-candidates-length))
       (should (eq 3 (point))))))
 
-(ert-deftest company-dont-require-match-idle ()
+(ert-deftest company-dont-require-match-when-idle ()
   (with-temp-buffer
     (insert "ab")
     (company-mode)
@@ -114,3 +114,41 @@
       (company-post-command)
       (should (eq nil company-candidates-length))
       (should (eq 4 (point))))))
+
+(ert-deftest company-auto-complete-explicit ()
+  (with-temp-buffer
+    (insert "ab")
+    (company-mode)
+    (let (company-frontends
+          (company-auto-complete 'company-explicit-action-p)
+          (company-auto-complete-chars '(? ))
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (case command
+                     (prefix (buffer-substring (point-min) (point)))
+                     (candidates '("abcd" "abef")))))))
+      (let (this-command)
+        (company-complete))
+      (let ((last-command-event ? ))
+        (self-insert-command 1))
+      (company-post-command)
+      (should (string= "abcd " (buffer-string))))))
+
+(ert-deftest company-no-auto-complete-when-idle ()
+  (with-temp-buffer
+    (insert "ab")
+    (company-mode)
+    (let (company-frontends
+          (company-auto-complete 'company-explicit-action-p)
+          (company-auto-complete-chars '(? ))
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (case command
+                     (prefix (buffer-substring (point-min) (point)))
+                     (candidates '("abcd" "abef")))))))
+      (company-idle-begin (current-buffer) (selected-window)
+                          (buffer-chars-modified-tick) (point))
+      (let ((last-command-event ? ))
+        (self-insert-command 1))
+      (company-post-command)
+      (should (string= "ab " (buffer-string))))))

commit eba32647fcbc74480d8955cd26381e3bdc7cf96d
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 25 02:03:55 2013 +0400

    company-calculate-candidates: Instead of company-candidates, use candidates

diff --git a/NEWS.md b/NEWS.md
index e05f109..fc1ffc2 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,9 @@
 # History of user-visible changes
 
+## Next
+
+* Fixed `company-require-match` mechanics.
+
 ## 2013-03-24 (0.6.2)
 
 * `global-company-mode` is now autoloaded.
diff --git a/company-tests.el b/company-tests.el
index 84b3503..fd89b58 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -66,11 +66,51 @@
     (company-mode)
     (should-error
      (company-begin-backend (lambda (command &rest ignore))))
-    (let ((company-backends
+    (let (company-frontends
+          (company-backends
            (list (lambda (command &optional arg)
                    (case command
                      (prefix "a")
                      (candidates '("a" "ab" "ac")))))))
-      (company-complete)
-      (setq this-command 'company-complete)
+      (let (this-command)
+        (company-complete))
+      (company-post-command)
       (should (eq 3 company-candidates-length)))))
+
+(ert-deftest company-require-match-explicit ()
+  (with-temp-buffer
+    (insert "ab")
+    (company-mode)
+    (let (company-frontends
+          (company-require-match 'company-explicit-action-p)
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (case command
+                     (prefix (buffer-substring (point-min) (point)))
+                     (candidates '("abc" "abd")))))))
+      (let (this-command)
+        (company-complete))
+      (let ((last-command-event ?e))
+        (self-insert-command 1))
+      (company-post-command)
+      (should (eq 2 company-candidates-length))
+      (should (eq 3 (point))))))
+
+(ert-deftest company-dont-require-match-idle ()
+  (with-temp-buffer
+    (insert "ab")
+    (company-mode)
+    (let (company-frontends
+          (company-require-match 'company-explicit-action-p)
+          (company-backends
+           (list (lambda (command &optional arg)
+                   (case command
+                     (prefix (buffer-substring (point-min) (point)))
+                     (candidates '("abc" "abd")))))))
+      (company-idle-begin (current-buffer) (selected-window)
+                          (buffer-chars-modified-tick) (point))
+      (let ((last-command-event ?e))
+        (self-insert-command 1))
+      (company-post-command)
+      (should (eq nil company-candidates-length))
+      (should (eq 4 (point))))))
diff --git a/company.el b/company.el
index e7e0540..674fc96 100644
--- a/company.el
+++ b/company.el
@@ -316,7 +316,7 @@ return the cons of buffer and buffer location, or of file 
and line
 number where the completion candidate was defined.
 
 `require-match': If this value is t, the user is not allowed to enter anything
-not offering as a candidate.  Use with care!  The default value nil gives the
+not offered as a candidate.  Use with care!  The default value nil gives the
 user that choice with `company-require-match'.  Return value 'never overrides
 that option the other way around.
 
@@ -841,14 +841,13 @@ can retrieve meta-data for them."
               (while c2
                 (setcdr c2 (progn (while (equal (pop c2) (car c2)))
                                   c2)))))))
-    (if (and candidates
-             (or (cdr candidates)
-                 (not (eq t (compare-strings (car candidates) nil nil
-                                             prefix nil nil ignore-case)))))
-        candidates
-      ;; Already completed and unique; don't start.
-      ;; FIXME: Not the right place? maybe when setting?
-      (and company-candidates t))))
+    (when candidates
+      (if (or (cdr candidates)
+              (not (eq t (compare-strings (car candidates) nil nil
+                                          prefix nil nil ignore-case))))
+          candidates
+        ;; Already completed and unique; don't start.
+        t))))
 
 (defun company-idle-begin (buf win tick pos)
   (and company-mode

commit 43d9131e07bceb60ab136074b1d32becb5be0c02
Author: Dmitry Gutov <address@hidden>
Date:   Sun Mar 24 03:52:56 2013 +0400

    company-eclim--project-name: Simplify

diff --git a/company-eclim.el b/company-eclim.el
index f8a55dc..e6e2fb6 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -98,11 +98,9 @@ eclim can only complete correctly when the buffer has been 
saved."
       (let ((dir (company-eclim--project-dir)))
         (when dir
           (setq company-eclim--project-name
-                (let ((project (loop for project in 
(company-eclim--project-list)
-                                     when (equal (cdr (assoc 'path project)) 
dir)
-                                     return project)))
-                  (when project
-                    (cdr (assoc 'name project)))))))))
+                (loop for project in (company-eclim--project-list)
+                      when (equal (cdr (assoc 'path project)) dir)
+                      return (cdr (assoc 'name project))))))))
 
 (defun company-eclim--candidates (prefix)
   (interactive "d")

commit c58998e8e4ebf93434c77b5b7b2691213a3533c8
Author: Dmitry Gutov <address@hidden>
Date:   Sun Mar 24 02:19:02 2013 +0400

    global-company-mode: extract turn-on function

diff --git a/NEWS.md b/NEWS.md
index a16a8df..e05f109 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,9 @@
 # History of user-visible changes
 
+## 2013-03-24 (0.6.2)
+
+* `global-company-mode` is now autoloaded.
+
 ## 2013-03-23 (0.6.1)
 
 * Documented `init` and `post-completion` back-end commands.
diff --git a/company.el b/company.el
index 0ddc945..e7e0540 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6.1
+;; Version: 0.6.2
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
@@ -551,9 +551,11 @@ keymap during active completions (`company-active-map'):
     (kill-local-variable 'company-point)))
 
 ;;;###autoload
-(define-globalized-minor-mode global-company-mode company-mode
-  (lambda () (unless (or noninteractive (eq (aref (buffer-name) 0) ?\s))
-          (company-mode 1))))
+(define-globalized-minor-mode global-company-mode company-mode company-mode-on)
+
+(defun company-mode-on ()
+  (unless (or noninteractive (eq (aref (buffer-name) 0) ?\s))
+    (company-mode 1)))
 
 (defsubst company-assert-enabled ()
   (unless company-mode

commit 4b2c71f7919166c4a37487c8859285a1f49f8a07
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 21:22:11 2013 +0400

    Silence some byte-compilation warnings

diff --git a/company-clang.el b/company-clang.el
index 3d28f0c..6844bb0 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -26,6 +26,7 @@
 ;;; Code:
 
 (require 'company)
+(require 'company-template)
 (eval-when-compile (require 'cl))
 
 (defcustom company-clang-executable
diff --git a/company-eclim.el b/company-eclim.el
index 599bf6e..f8a55dc 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -31,6 +31,7 @@
 ;;; Code:
 
 (require 'company)
+(require 'company-template)
 (eval-when-compile (require 'cl))
 
 (defun company-eclim-executable-find ()
@@ -97,10 +98,9 @@ eclim can only complete correctly when the buffer has been 
saved."
       (let ((dir (company-eclim--project-dir)))
         (when dir
           (setq company-eclim--project-name
-                (let ((project (find-if (lambda (project)
-                                          (equal (cdr (assoc 'path project))
-                                                 dir))
-                                        (company-eclim--project-list))))
+                (let ((project (loop for project in 
(company-eclim--project-list)
+                                     when (equal (cdr (assoc 'path project)) 
dir)
+                                     return project)))
                   (when project
                     (cdr (assoc 'name project)))))))))
 
diff --git a/company-elisp.el b/company-elisp.el
index ec3161d..986cd3d 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -28,6 +28,7 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 (require 'help-mode)
+(require 'find-func)
 
 (defcustom company-elisp-detect-function-context t
   "If enabled, offer Lisp functions only in appropriate contexts.
diff --git a/company.el b/company.el
index 60a3aee..0ddc945 100644
--- a/company.el
+++ b/company.el
@@ -656,10 +656,10 @@ keymap during active completions (`company-active-map'):
     (apply 'company--multi-backend-adapter company-backend args)))
 
 (defun company--multi-backend-adapter (backends command &rest args)
-  (let ((backends (remove-if (lambda (b)
-                               (and (symbolp b)
-                                    (eq 'failed (get b 'company-init))))
-                             backends)))
+  (let ((backends (loop for b in backends
+                        when (not (and (symbolp b)
+                                       (eq 'failed (get b 'company-init))))
+                        collect b)))
     (case command
       (candidates
        (loop for backend in backends
@@ -2000,9 +2000,5 @@ Returns a negative number if the tooltip should be 
displayed above point."
     (post-command (company-echo-show-when-idle 'company-fetch-metadata))
     (hide (company-echo-hide))))
 
-;; templates 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(autoload 'company-template-declare-template "company-template")
-
 (provide 'company)
 ;;; company.el ends here

commit c985070615a9be6a350708855fe2454906317c78
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 20:38:15 2013 +0400

    Autoload global-company-mode

diff --git a/company.el b/company.el
index facf48b..60a3aee 100644
--- a/company.el
+++ b/company.el
@@ -550,6 +550,7 @@ keymap during active completions (`company-active-map'):
     (company-cancel)
     (kill-local-variable 'company-point)))
 
+;;;###autoload
 (define-globalized-minor-mode global-company-mode company-mode
   (lambda () (unless (or noninteractive (eq (aref (buffer-name) 0) ?\s))
           (company-mode 1))))

commit 3dd60d13c7bb4af33d1a0b0ff320d39039cfe9a0
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 08:11:13 2013 +0400

    Release 0.6.1

diff --git a/NEWS.md b/NEWS.md
index 5d86295..a16a8df 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,6 @@
 # History of user-visible changes
 
-## Next
+## 2013-03-23 (0.6.1)
 
 * Documented `init` and `post-completion` back-end commands.
 * `company-eclim` and `company-clang` only expand the template on explicit user
diff --git a/company.el b/company.el
index 33c6c95..facf48b 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nikolaj Schumacher
 ;; Maintainer: Dmitry Gutov <address@hidden>
-;; Version: 0.6
+;; Version: 0.6.1
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x

commit 509f231cb803209017a31299343c2a3317fc2a4d
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 08:07:42 2013 +0400

    company-eclim: Work when Eclim was launched late

diff --git a/company-eclim.el b/company-eclim.el
index 6d89369..599bf6e 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -60,7 +60,7 @@ eclim can only complete correctly when the buffer has been 
saved."
 (defvar company-eclim--project-dir 'unknown)
 (make-variable-buffer-local 'company-eclim--project-dir)
 
-(defvar company-eclim--project-name 'unknown)
+(defvar company-eclim--project-name nil)
 (make-variable-buffer-local 'company-eclim--project-name)
 
 (defvar company-eclim--doc nil)
@@ -93,15 +93,16 @@ eclim can only complete correctly when the buffer has been 
saved."
     company-eclim--project-dir))
 
 (defun company-eclim--project-name ()
-  (if (eq company-eclim--project-name 'unknown)
-      (setq company-eclim--project-name
-            (let ((project (find-if (lambda (project)
-                                      (equal (cdr (assoc 'path project))
-                                             (company-eclim--project-dir)))
-                                    (company-eclim--project-list))))
-              (when project
-                (cdr (assoc 'name project)))))
-    company-eclim--project-name))
+  (or company-eclim--project-name
+      (let ((dir (company-eclim--project-dir)))
+        (when dir
+          (setq company-eclim--project-name
+                (let ((project (find-if (lambda (project)
+                                          (equal (cdr (assoc 'path project))
+                                                 dir))
+                                        (company-eclim--project-list))))
+                  (when project
+                    (cdr (assoc 'name project)))))))))
 
 (defun company-eclim--candidates (prefix)
   (interactive "d")

commit 29fbc711eda6a3c43033ef4e8c3a4603aff3db87
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 07:58:25 2013 +0400

    company--multi-backend-adapter: safe > fast
    
    Fixes list corruption when running test company-multi-backend-with-lambdas
    repeatedly.

diff --git a/company.el b/company.el
index 17b48a0..33c6c95 100644
--- a/company.el
+++ b/company.el
@@ -664,7 +664,7 @@ keymap during active completions (`company-active-map'):
        (loop for backend in backends
              when (equal (funcall backend 'prefix)
                          (car args))
-             nconc (apply backend 'candidates args)))
+             append (apply backend 'candidates args)))
       (sorted nil)
       (duplicates t)
       (otherwise

commit 24c73b930aff562cacf9c068b7f1c9ab6521eab2
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 07:12:07 2013 +0400

    company-begin-backend: unset company-backend on error

diff --git a/company-tests.el b/company-tests.el
index 7bcc0a0..84b3503 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -1,6 +1,6 @@
 ;;; company-tests.el --- company-mode tests
 
-;; Copyright (C) 2011  Free Software Foundation, Inc.
+;; Copyright (C) 2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -59,3 +59,18 @@
                    (prefix "z")
                    (candidates '("c" "d")))))))
     (should (equal (company-call-backend 'candidates "z") '("a" "b" "c" 
"d")))))
+
+(ert-deftest company-begin-backend-failure-doesnt-break-company-backends ()
+  (with-temp-buffer
+    (insert "a")
+    (company-mode)
+    (should-error
+     (company-begin-backend (lambda (command &rest ignore))))
+    (let ((company-backends
+           (list (lambda (command &optional arg)
+                   (case command
+                     (prefix "a")
+                     (candidates '("a" "ab" "ac")))))))
+      (company-complete)
+      (setq this-command 'company-complete)
+      (should (eq 3 company-candidates-length)))))
diff --git a/company.el b/company.el
index 5d64f3a..17b48a0 100644
--- a/company.el
+++ b/company.el
@@ -1522,7 +1522,9 @@ To show the number next to the candidates in some 
back-ends, enable
   (setq company-backend backend)
   ;; Return non-nil if active.
   (or (company-manual-begin)
-      (error "Cannot complete at point")))
+      (progn
+        (setq company-backend nil)
+        (error "Cannot complete at point"))))
 
 (defun company-begin-with (candidates
                            &optional prefix-length require-match callback)

commit 9a2dba0b6ef2f9b6a0191c8a43c9dc083d31b804
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 04:45:48 2013 +0400

    Support lambda values in grouped backends list

diff --git a/company-tests.el b/company-tests.el
index 691e3ae..7bcc0a0 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -47,3 +47,15 @@
     (should (eq nil (company--good-prefix-p 'stop)))
     (should (eq t (company--good-prefix-p '("foo" . 5))))
     (should (eq nil (company--good-prefix-p '("foo" . 4))))))
+
+(ert-deftest company-multi-backend-with-lambdas ()
+  (let ((company-backend
+         (list (lambda (command &optional arg &rest ignore)
+                 (case command
+                   (prefix "z")
+                   (candidates '("a" "b"))))
+               (lambda (command &optional arg &rest ignore)
+                 (case command
+                   (prefix "z")
+                   (candidates '("c" "d")))))))
+    (should (equal (company-call-backend 'candidates "z") '("a" "b" "c" 
"d")))))
diff --git a/company.el b/company.el
index b60db36..5d64f3a 100644
--- a/company.el
+++ b/company.el
@@ -655,7 +655,9 @@ keymap during active completions (`company-active-map'):
     (apply 'company--multi-backend-adapter company-backend args)))
 
 (defun company--multi-backend-adapter (backends command &rest args)
-  (let ((backends (remove-if (lambda (b) (eq 'failed (get b 'company-init)))
+  (let ((backends (remove-if (lambda (b)
+                               (and (symbolp b)
+                                    (eq 'failed (get b 'company-init))))
                              backends)))
     (case command
       (candidates

commit 6d979b80e37d66b83172feaa1cdb8b5b994619c0
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 02:43:27 2013 +0400

    Handle 'stop prefix directly

diff --git a/company-tests.el b/company-tests.el
index 1f5db14..691e3ae 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -29,7 +29,7 @@
 (require 'company)
 (require 'company-keywords)
 
-(ert-deftest sorted-keywords ()
+(ert-deftest company-sorted-keywords ()
   "Test that keywords in `company-keywords-alist' are in alphabetical order."
   (dolist (pair company-keywords-alist)
     (when (consp (cdr pair))
@@ -38,3 +38,12 @@
           (should (not (equal prev next)))
           (should (string< prev next))
           (setq prev next))))))
+
+(ert-deftest company-good-prefix ()
+  (let ((company-minimum-prefix-length 5)
+        company--explicit-action)
+    (should (eq t (company--good-prefix-p "address@hidden")))
+    (should (eq nil (company--good-prefix-p "abcd")))
+    (should (eq nil (company--good-prefix-p 'stop)))
+    (should (eq t (company--good-prefix-p '("foo" . 5))))
+    (should (eq nil (company--good-prefix-p '("foo" . 4))))))
diff --git a/company.el b/company.el
index 4a93d62..b60db36 100644
--- a/company.el
+++ b/company.el
@@ -954,8 +954,9 @@ can retrieve meta-data for them."
 
 (defun company--good-prefix-p (prefix)
   (and (or (company-explicit-action-p)
-           (>= (or (cdr-safe prefix) (length prefix))
-               company-minimum-prefix-length))
+           (unless (eq prefix 'stop)
+             (>= (or (cdr-safe prefix) (length prefix))
+                 company-minimum-prefix-length)))
        (stringp (or (car-safe prefix) prefix))))
 
 (defun company--continue ()

commit 6d14ffbfd6c1dc061c291d630ed63d3b2241c043
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 02:34:50 2013 +0400

    Document 'init and 'post-completion

diff --git a/.dir-locals.el b/.dir-locals.el
index 3a4c010..0f821cf 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,3 +1,4 @@
 ((nil . ((indent-tabs-mode . nil)
          (fill-column . 80)
-         (sentence-end-double-space . t))))
+         (sentence-end-double-space . t)
+         (emacs-lisp-docstring-fill-column . t))))
diff --git a/NEWS.md b/NEWS.md
index 157e6de..5d86295 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* Documented `init` and `post-completion` back-end commands.
 * `company-eclim` and `company-clang` only expand the template on explicit user
   action (such as `company-complete-{selection,number,mouse}`).
 * `company-template` has some breaking changes.  When point is at one of the
diff --git a/company.el b/company.el
index b434747..4a93d62 100644
--- a/company.el
+++ b/company.el
@@ -320,6 +320,14 @@ not offering as a candidate.  Use with care!  The default 
value nil gives the
 user that choice with `company-require-match'.  Return value 'never overrides
 that option the other way around.
 
+`init': Called once for each buffer, the back-end can check for external
+programs and files and load any required libraries.  Raising an error here will
+show up in message log once, and the backend will not be used for completion.
+
+`post-completion': Called after a completion candidate has been inserted into
+the buffer.  The second argument is the candidate.  Can be used to modify it,
+e.g. to expand a snippet.
+
 The back-end should return nil for all commands it does not support or
 does not know about.  It should also be callable interactively and use
 `company-begin-backend' to start itself in that case."

commit 809c7833579de5217069c6e678c30e0667c22a9a
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 23 00:45:12 2013 +0400

    And another rename. Hopefully, this one will stick.

diff --git a/company-clang.el b/company-clang.el
index fc426d3..3d28f0c 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -245,7 +245,7 @@ Completions only work correctly when the buffer has been 
saved.
                "#]" " "
                (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
                t))))
-    (safe (and (derived-mode-p 'objc-mode)
+    (crop (and (derived-mode-p 'objc-mode)
                (string-match ":" arg)
                (substring arg 0 (match-beginning 0))))
     (post-completion (and (derived-mode-p 'objc-mode)
diff --git a/company-eclim.el b/company-eclim.el
index fd74a01..6d89369 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -167,7 +167,7 @@ Completions only work correctly when the buffer has been 
saved.
     (meta (company-eclim--meta arg))
     ;; because "" doesn't return everything
     (no-cache (equal arg ""))
-    (safe (when (string-match "(" arg)
+    (crop (when (string-match "(" arg)
             (substring arg 0 (match-beginning 0))))
     (post-completion (when (string-match "([^)]" arg)
                        (company-eclim--templatify arg)))))
diff --git a/company.el b/company.el
index ff4f29f..b434747 100644
--- a/company.el
+++ b/company.el
@@ -797,7 +797,7 @@ can retrieve meta-data for them."
     (setq company-candidates nil)))
 
 (defun company--safe-candidate (str)
-  (or (company-call-backend 'safe str)
+  (or (company-call-backend 'crop str)
       str))
 
 (defun company-calculate-candidates (prefix)

commit 06ca7849f29189687aa380a2c3d9c84c7859aabe
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 22 09:07:04 2013 +0400

    Introduce `company--auto-completion', rename 'common to 'safe

diff --git a/NEWS.md b/NEWS.md
index f53a9fe..157e6de 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,13 +2,14 @@
 
 ## Next
 
+* `company-eclim` and `company-clang` only expand the template on explicit user
+  action (such as `company-complete-{selection,number,mouse}`).
 * `company-template` has some breaking changes.  When point is at one of the
   fields, it's displayed at the beginning, not right after it; `<tab>` jumps to
   the next field, `forward-word` and `subword-forward` remappings are removed;
   when you jump to the next field, if the current one hasn't been edited, the
   overlay gets removed but the text remains.
-* `company-eclim` shows method overloads and inserts templates for calls.
-* `company-clang` ObjC arguments template insertion now requires explicit user 
action.
+* `company-eclim` shows method overloads and expands templates for calls.
 * `company-clang-objc-templatify` does not insert spaces after colons anymore.
 * `company-clang` is now only initialized in supported buffers.
   So, no error messages if you don't have Clang until you open a C file.
diff --git a/company-clang.el b/company-clang.el
index 9dbd12d..fc426d3 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -245,9 +245,9 @@ Completions only work correctly when the buffer has been 
saved.
                "#]" " "
                (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
                t))))
-    (common (and (derived-mode-p 'objc-mode)
-                 (string-match ":" arg)
-                 (substring arg 0 (match-beginning 0))))
+    (safe (and (derived-mode-p 'objc-mode)
+               (string-match ":" arg)
+               (substring arg 0 (match-beginning 0))))
     (post-completion (and (derived-mode-p 'objc-mode)
                           (string-match ":" arg)
                           (company-clang-objc-templatify arg)))))
diff --git a/company-eclim.el b/company-eclim.el
index c481dd9..fd74a01 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -167,8 +167,8 @@ Completions only work correctly when the buffer has been 
saved.
     (meta (company-eclim--meta arg))
     ;; because "" doesn't return everything
     (no-cache (equal arg ""))
-    (common (when (string-match "(" arg)
-              (substring arg 0 (match-beginning 0))))
+    (safe (when (string-match "(" arg)
+            (substring arg 0 (match-beginning 0))))
     (post-completion (when (string-match "([^)]" arg)
                        (company-eclim--templatify arg)))))
 
diff --git a/company.el b/company.el
index fe87eed..ff4f29f 100644
--- a/company.el
+++ b/company.el
@@ -696,6 +696,10 @@ keymap during active completions (`company-active-map'):
   "Non-nil, if explicit completion took place.")
 (make-variable-buffer-local 'company--explicit-action)
 
+(defvar company--auto-completion nil
+  "Non-nil when current candidate is being completed automatically.
+Controlled by `company-auto-complete'.")
+
 (defvar company--point-max nil)
 (make-variable-buffer-local 'company--point-max)
 
@@ -787,12 +791,15 @@ can retrieve meta-data for them."
   (push (cons company-prefix company-candidates) company-candidates-cache)
   ;; Calculate common.
   (let ((completion-ignore-case (company-call-backend 'ignore-case)))
-    (let ((common (try-completion company-prefix company-candidates)))
-      (setq company-common (or (company-call-backend 'common common)
-                               common))))
+    (setq company-common (company--safe-candidate
+                          (try-completion company-prefix company-candidates))))
   (when (eq company-common t)
     (setq company-candidates nil)))
 
+(defun company--safe-candidate (str)
+  (or (company-call-backend 'safe str)
+      str))
+
 (defun company-calculate-candidates (prefix)
   (let ((candidates (cdr (assoc prefix company-candidates-cache)))
         (ignore-case (company-call-backend 'ignore-case)))
@@ -922,7 +929,8 @@ can retrieve meta-data for them."
         ;; auto-complete
         (save-excursion
           (goto-char company-point)
-          (company-complete-selection)
+          (let ((company--auto-completion t))
+            (company-complete-selection))
           nil))
        ((and (company--string-incremental-p company-prefix new-prefix)
              (company-require-match-p))
@@ -1334,7 +1342,10 @@ and invoke the normal binding."
   "Complete the selected candidate."
   (interactive)
   (when (company-manual-begin)
-    (company-finish (nth company-selection company-candidates))))
+    (let ((result (nth company-selection company-candidates)))
+      (when company--auto-completion
+        (setq result (company--safe-candidate result)))
+      (company-finish result))))
 
 (defun company-complete-common ()
   "Complete the common part of all candidates."

commit 23ed20ed236761b2aee517bca01810b9324698de
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 22 08:01:56 2013 +0400

    company-eclim: Don't auto-complete common part after the paren

diff --git a/company-eclim.el b/company-eclim.el
index cda300c..c481dd9 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -167,6 +167,8 @@ Completions only work correctly when the buffer has been 
saved.
     (meta (company-eclim--meta arg))
     ;; because "" doesn't return everything
     (no-cache (equal arg ""))
+    (common (when (string-match "(" arg)
+              (substring arg 0 (match-beginning 0))))
     (post-completion (when (string-match "([^)]" arg)
                        (company-eclim--templatify arg)))))
 

commit 0970c3d32dc3aff696f41d9a4fe9050c2318d65b
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 22 05:58:53 2013 +0400

    company-template: Bring closer to yasnippet behavior

diff --git a/NEWS.md b/NEWS.md
index 57019cd..f53a9fe 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,12 +2,17 @@
 
 ## Next
 
-* `company-eclim` shows method overloads and inserts call templates with 
placeholders.
+* `company-template` has some breaking changes.  When point is at one of the
+  fields, it's displayed at the beginning, not right after it; `<tab>` jumps to
+  the next field, `forward-word` and `subword-forward` remappings are removed;
+  when you jump to the next field, if the current one hasn't been edited, the
+  overlay gets removed but the text remains.
+* `company-eclim` shows method overloads and inserts templates for calls.
 * `company-clang` ObjC arguments template insertion now requires explicit user 
action.
 * `company-clang-objc-templatify` does not insert spaces after colons anymore.
 * `company-clang` is now only initialized in supported buffers.
   So, no error messages if you don't have Clang until you open a C file.
-* `company-clang` recognizes Clang included with recent Xcode.
+* `company-clang` recognizes Clang included in recent Xcode.
 * New commands `company-select-previous-or-abort` and
   `company-select-next-or-abort`, bound to `<up>` and `<down>`.
 
diff --git a/company-clang.el b/company-clang.el
index 6135f24..9dbd12d 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -198,14 +198,20 @@ Prefix files (-include ...) can be selected with
 (defun company-clang-objc-templatify (selector)
   (let* ((end (point))
          (beg (- (point) (length selector)))
-         (templ (company-template-declare-template beg end)))
+         (templ (company-template-declare-template beg end))
+         (cnt 0))
     (save-excursion
       (goto-char beg)
       (while (search-forward ":" end t)
-        (replace-match ": ")
-        (incf end)
-        (company-template-add-field templ (1- (match-end 0)) "<arg>"))
-      (delete-char -1))
+        (let* ((name (format "arg%d" cnt))
+               (len (length name)))
+          (incf end len)
+          (company-template-add-field templ (match-end 0) name)
+          (goto-char (+ (match-end 0) len))
+          (when (< (point) end)
+            (insert " ")
+            (incf end))
+          (incf cnt))))
     (company-template-move-to-first templ)))
 
 (defun company-clang (command &optional arg &rest ignored)
diff --git a/company-eclim.el b/company-eclim.el
index 1637f3c..cda300c 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -141,12 +141,11 @@ eclim can only complete correctly when the buffer has 
been saved."
          (templ (company-template-declare-template beg end)))
     (save-excursion
       (goto-char beg)
-      (while (re-search-forward "\\([(,] ?\\)\\(?:[^ ]+ \\)\\([^ ,)]*\\)" end 
t)
-        (let ((name (match-string 2)))
+      (while (re-search-forward "\\([(,] ?\\)\\([^ ]+ \\)\\([^ ,)]*\\)" end t)
+        (let ((name (match-string 3)))
           (replace-match "\\1" t)
-          (decf end (- (length (match-string 0))
-                       (length (match-string 1))))
-          (company-template-add-field templ (point) (format "<%s>" name)))))
+          (decf end (length (match-string 2)))
+          (company-template-add-field templ (point) name))))
     (company-template-move-to-first templ)))
 
 (defun company-eclim (command &optional arg &rest ignored)
diff --git a/company-template.el b/company-template.el
index 69eac7c..05389ac 100644
--- a/company-template.el
+++ b/company-template.el
@@ -31,14 +31,12 @@
 
 (defvar company-template-nav-map
   (let ((keymap (make-sparse-keymap)))
-    (define-key keymap [remap forward-word] 'company-template-forward-field)
-    (define-key keymap [remap subword-forward] 'company-template-forward-field)
-    ;; M-n
+    (define-key keymap [tab] 'company-template-forward-field)
     keymap))
 
 ;; interactive 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defsubst company-template-templates-at (pos)
+(defun company-template-templates-at (pos)
   (let (os)
     (dolist (o (overlays-at pos))
       (when (overlay-get o 'company-template-fields)
@@ -53,19 +51,22 @@
 
 (defun company-template-forward-field ()
   (interactive)
-  (let* ((templates (company-template-templates-at (point)))
+  (let* ((start (point))
+         (templates (company-template-templates-at (point)))
          (minimum (apply 'max (mapcar 'overlay-end templates)))
-         (fields (apply 'append
-                        (mapcar (lambda (templ)
-                                  (overlay-get templ 'company-template-fields))
-                                templates))))
+         (fields (loop for templ in templates
+                       append (overlay-get templ 'company-template-fields))))
     (dolist (pos (mapcar 'overlay-start fields))
       (and pos
            (> pos (point))
            (< pos minimum)
            (setq minimum pos)))
     (push-mark)
-    (goto-char minimum)))
+    (goto-char minimum)
+    (let ((field (loop for ovl in (overlays-at start)
+                       when (overlay-get ovl 'company-template-parent)
+                       return ovl)))
+      (company-template-remove-field field))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -76,6 +77,7 @@
   (let ((ov (make-overlay beg end)))
     ;; (overlay-put ov 'face 'highlight)
     (overlay-put ov 'keymap company-template-nav-map)
+    (overlay-put ov 'priority 101)
     (overlay-put ov 'evaporate t)
     (push ov company-template--buffer-templates)
     (add-hook 'post-command-hook 'company-template-post-command nil t)
@@ -91,42 +93,47 @@
 (defun company-template-add-field (templ pos text)
   (assert templ)
   (save-excursion
-    ;; (goto-char pos)
-    (let ((ov (make-overlay pos pos))
-          (siblings (overlay-get templ 'company-template-fields))
-          (label (propertize text 'face 'company-template-field
-                             'company-template-parent templ)))
-      (overlay-put ov 'face 'highlight)
-      (add-text-properties 0 1 '(cursor t) label)
-      (overlay-put ov 'after-string label)
+    (save-excursion
+      (goto-char pos)
+      (insert text)
+      (when (> (point) (overlay-end templ))
+        (move-overlay templ (overlay-start templ) (point))))
+    (let ((ov (make-overlay pos (+ pos (length text))))
+          (siblings (overlay-get templ 'company-template-fields)))
       ;; (overlay-put ov 'evaporate t)
       (overlay-put ov 'intangible t)
+      (overlay-put ov 'face 'company-template-field)
       (overlay-put ov 'company-template-parent templ)
-      (overlay-put ov 'insert-in-front-hooks '(company-template-remove))
+      (overlay-put ov 'insert-in-front-hooks '(company-template-insert-hook))
       (push ov siblings)
       (overlay-put templ 'company-template-fields siblings))))
 
-(defun company-template-remove-field (field)
-  (when (overlayp field)
-    ;; (delete-region (overlay-start field) (overlay-end field))
-    (delete-overlay field))
-  ;; TODO: unlink
-  )
+(defun company-template-remove-field (ovl &optional clear)
+  (when (overlayp ovl)
+    (when (overlay-buffer ovl)
+      (when clear
+        (delete-region (overlay-start ovl) (overlay-end ovl)))
+      (delete-overlay ovl))
+    (let* ((templ (overlay-get ovl 'company-template-parent))
+           (siblings (overlay-get templ 'company-template-fields)))
+      (setq siblings (delq ovl siblings))
+      (overlay-put templ 'company-template-fields siblings))))
 
 (defun company-template-clean-up (&optional pos)
   "Clean up all templates that don't contain POS."
   (unless pos (setq pos (point)))
   (let ((local-ovs (overlays-in (- pos 2) pos)))
     (dolist (templ company-template--buffer-templates)
-      (unless (memq templ local-ovs)
+      (unless (and (memq templ local-ovs)
+                   (overlay-get templ 'company-template-fields))
         (company-template-remove-template templ)))))
 
 ;; hooks 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun company-template-remove (overlay after-p beg end &optional r)
+(defun company-template-insert-hook (ovl after-p &rest ignore)
   "Called when a snippet input prompt is modified."
-  (when after-p
-    (delete-overlay overlay)))
+  (unless after-p
+    (company-template-remove-field ovl t)))
 
 (defun company-template-post-command ()
   (company-template-clean-up)

commit 56a1a36395f0d1bffab96532d71e4345eb8076eb
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 22 01:09:58 2013 +0400

    company-eclim: Show overloads, insert call templates

diff --git a/NEWS.md b/NEWS.md
index 0be44ad..57019cd 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* `company-eclim` shows method overloads and inserts call templates with 
placeholders.
 * `company-clang` ObjC arguments template insertion now requires explicit user 
action.
 * `company-clang-objc-templatify` does not insert spaces after colons anymore.
 * `company-clang` is now only initialized in supported buffers.
diff --git a/company-eclim.el b/company-eclim.el
index e5bce3b..1637f3c 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -116,25 +116,38 @@ eclim can only complete correctly when the buffer has 
been saved."
                                    "-p" (company-eclim--project-name)
                                    "-f" project-file))
     (setq company-eclim--doc
-          (cdr (assoc 'completions
-                      (company-eclim--call-process
-                       "java_complete" "-p" (company-eclim--project-name)
-                       "-f" project-file
-                       "-o" (number-to-string (1- (point)))
-                       "-e" "utf-8"
-                       "-l" "standard")))))
+          (make-hash-table :test 'equal))
+    (dolist (item (cdr (assoc 'completions
+                              (company-eclim--call-process
+                               "java_complete" "-p" 
(company-eclim--project-name)
+                               "-f" project-file
+                               "-o" (number-to-string (1- (point)))
+                               "-e" "utf-8"
+                               "-l" "standard"))))
+      (let* ((meta (cdr (assoc 'info item)))
+             (completion meta))
+        (when (string-match " [:-]" completion)
+          (setq completion (substring completion 0 (match-beginning 0))))
+        (puthash completion meta company-eclim--doc))))
   (let ((completion-ignore-case nil))
-    ;; TODO: Handle overloaded methods somehow. Show one candidate per 
overload?
-    ;; That would look nice, but kinda useless: a bunch of candidates for the
-    ;; same completion. Maybe do expansion like 
`company-clang-objc-templatify'.
-    (all-completions prefix (mapcar (lambda (item) (cdr (assoc 'completion 
item)))
-                                    company-eclim--doc))))
+    (all-completions prefix company-eclim--doc)))
 
 (defun company-eclim--meta (candidate)
-  (cdr (assoc 'info (find-if
-                     (lambda (item) (equal (cdr (assoc 'completion item))
-                                      arg))
-                     company-eclim--doc))))
+  (gethash candidate company-eclim--doc))
+
+(defun company-eclim--templatify (call)
+  (let* ((end (point))
+         (beg (- (point) (length call)))
+         (templ (company-template-declare-template beg end)))
+    (save-excursion
+      (goto-char beg)
+      (while (re-search-forward "\\([(,] ?\\)\\(?:[^ ]+ \\)\\([^ ,)]*\\)" end 
t)
+        (let ((name (match-string 2)))
+          (replace-match "\\1" t)
+          (decf end (- (length (match-string 0))
+                       (length (match-string 1))))
+          (company-template-add-field templ (point) (format "<%s>" name)))))
+    (company-template-move-to-first templ)))
 
 (defun company-eclim (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for eclim.
@@ -153,9 +166,10 @@ Completions only work correctly when the buffer has been 
saved.
                  (or (company-grab-symbol) 'stop)))
     (candidates (company-eclim--candidates arg))
     (meta (company-eclim--meta arg))
-    (duplicates t)
     ;; because "" doesn't return everything
-    (no-cache (equal arg ""))))
+    (no-cache (equal arg ""))
+    (post-completion (when (string-match "([^)]" arg)
+                       (company-eclim--templatify arg)))))
 
 (provide 'company-eclim)
 ;;; company-eclim.el ends here

commit 1f30a34741c61f35b18d66b6b506bc2a8242f858
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 21 21:10:08 2013 +0400

    Add experimental backend command 'common

diff --git a/NEWS.md b/NEWS.md
index de36cbd..0be44ad 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* `company-clang` ObjC arguments template insertion now requires explicit user 
action.
 * `company-clang-objc-templatify` does not insert spaces after colons anymore.
 * `company-clang` is now only initialized in supported buffers.
   So, no error messages if you don't have Clang until you open a C file.
diff --git a/company-clang.el b/company-clang.el
index 7fc66a9..6135f24 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -239,6 +239,9 @@ Completions only work correctly when the buffer has been 
saved.
                "#]" " "
                (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
                t))))
+    (common (and (derived-mode-p 'objc-mode)
+                 (string-match ":" arg)
+                 (substring arg 0 (match-beginning 0))))
     (post-completion (and (derived-mode-p 'objc-mode)
                           (string-match ":" arg)
                           (company-clang-objc-templatify arg)))))
diff --git a/company.el b/company.el
index df758e1..fe87eed 100644
--- a/company.el
+++ b/company.el
@@ -787,7 +787,9 @@ can retrieve meta-data for them."
   (push (cons company-prefix company-candidates) company-candidates-cache)
   ;; Calculate common.
   (let ((completion-ignore-case (company-call-backend 'ignore-case)))
-    (setq company-common (try-completion company-prefix company-candidates)))
+    (let ((common (try-completion company-prefix company-candidates)))
+      (setq company-common (or (company-call-backend 'common common)
+                               common))))
   (when (eq company-common t)
     (setq company-candidates nil)))
 
@@ -823,9 +825,9 @@ can retrieve meta-data for them."
              (or (cdr candidates)
                  (not (eq t (compare-strings (car candidates) nil nil
                                              prefix nil nil ignore-case)))))
-        ;; Don't start when already completed and unique.
         candidates
-      ;; Not the right place? maybe when setting?
+      ;; Already completed and unique; don't start.
+      ;; FIXME: Not the right place? maybe when setting?
       (and company-candidates t))))
 
 (defun company-idle-begin (buf win tick pos)

commit 9bf653e045719b0823de5c809bcf0b8751f8c3a8
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 21 19:57:26 2013 +0400

    company-clang-objc-templatify: No extra space before args

diff --git a/NEWS.md b/NEWS.md
index a14f605..de36cbd 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* `company-clang-objc-templatify` does not insert spaces after colons anymore.
 * `company-clang` is now only initialized in supported buffers.
   So, no error messages if you don't have Clang until you open a C file.
 * `company-clang` recognizes Clang included with recent Xcode.
diff --git a/company-clang.el b/company-clang.el
index 6b80ef0..7fc66a9 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -202,8 +202,8 @@ Prefix files (-include ...) can be selected with
     (save-excursion
       (goto-char beg)
       (while (search-forward ":" end t)
-        (replace-match ":  ")
-        (incf end 2)
+        (replace-match ": ")
+        (incf end)
         (company-template-add-field templ (1- (match-end 0)) "<arg>"))
       (delete-char -1))
     (company-template-move-to-first templ)))

commit 9ff7b4160ffc4d7639f8b184f58d0f5a4abe897a
Author: Leo Liu <address@hidden>
Date:   Thu Mar 21 12:29:19 2013 +0800

    Fix last change

diff --git a/ggtags.el b/ggtags.el
index 6cac43e..9992eaf 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -132,7 +132,7 @@ Return -1 if it does not exist."
   (> (ggtags-get-timestamp key)
      (or (fourth (ggtags-cache-get key)) 0)))
 
-(defvar-local ggtags-root-directory 'init
+(defvar-local ggtags-root-directory 'unset
   "Internal; use function `ggtags-root-directory' instead.")
 
 ;;;###autoload
@@ -406,7 +406,7 @@ When called with prefix, ask the name and kind of tag."
          (message "%d %s killed" count (if (= count 1) "buffer" "buffers")))))
 
 (defun ggtags-after-save-function ()
-  (let ((root (ggtags-root-directory)))
+  (let ((root (with-demoted-errors (ggtags-root-directory))))
     (and root (ggtags-cache-mark-dirty root t))))
 
 (defvar ggtags-tag-overlay nil)
@@ -456,10 +456,10 @@ When called with prefix, ask the name and kind of tag."
   :lighter (:eval (if ggtags-navigation-mode "" " GG"))
   (if ggtags-mode
       (progn
-        (or (ggtags-root-directory)
-            (message "File GTAGS not found"))
         (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
-        (add-hook 'post-command-hook 'ggtags-post-command-function nil t))
+        (if (executable-find "global")
+            (add-hook 'post-command-hook 'ggtags-post-command-function nil t)
+          (message "Failed to find GNU Global")))
     (remove-hook 'after-save-hook 'ggtags-after-save-function t)
     (remove-hook 'post-command-hook 'ggtags-post-command-function t)
     (and (overlayp ggtags-tag-overlay)
@@ -481,8 +481,8 @@ When called with prefix, ask the name and kind of tag."
   (when buffer-file-name
     (let ((file (file-truename buffer-file-name)))
       (with-temp-buffer
-        (when (zerop (with-demoted-errors
-                       (call-process "global" nil t nil "-f" file)))
+        (when (with-demoted-errors
+                (zerop (call-process "global" nil t nil "-f" file)))
           (goto-char (point-min))
           (loop while (re-search-forward
                        "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)" nil t)
@@ -503,7 +503,7 @@ When called with prefix, ask the name and kind of tag."
                       (point))
       (setq he-expand-list
             (and (not (equal he-search-string ""))
-                 (ggtags-root-directory)
+                 (with-demoted-errors (ggtags-root-directory))
                  (sort (all-completions he-search-string
                                         (ggtags-tag-names))
                        'string-lessp))))

commit 1868d5c64e9fbc764bb668fd8077b6f4829464b3
Author: Leo Liu <address@hidden>
Date:   Thu Mar 21 11:14:29 2013 +0800

    Remove ggtags-ignore-file-error and its uses
    
    If `gtags' or `global' that ggtags-mode relies on can not be found,
    users should get the error.
    
    See https://github.com/leoliu/ggtags/issues/2

diff --git a/ggtags.el b/ggtags.el
index ea58b52..6cac43e 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6.1
+;; Version: 0.6.2
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -79,15 +79,9 @@ If nil, use Emacs default."
 (defvar ggtags-global-error "match"
   "Stem of message to print when no matches are found.")
 
-(defmacro ggtags-ignore-file-error (&rest body)
-  (declare (indent 0))
-  `(condition-case nil
-       (progn ,@body)
-     (file-error nil)))
-
 ;; http://thread.gmane.org/gmane.comp.gnu.global.bugs/1518
 (defvar ggtags-global-has-path-style    ; introduced in global 6.2.8
-  (ggtags-ignore-file-error
+  (with-demoted-errors                  ; in case `global' not found
     (and (string-match-p "^--path-style "
                          (shell-command-to-string "global --help"))
          t))
@@ -146,11 +140,10 @@ Return -1 if it does not exist."
   (if (string-or-null-p ggtags-root-directory)
       ggtags-root-directory
     (setq ggtags-root-directory
-          (ggtags-ignore-file-error
-           (with-temp-buffer
-             (when (zerop (call-process "global" nil (list t nil) nil "-pr"))
-               (file-name-as-directory
-                (comment-string-strip (buffer-string) t t))))))))
+          (with-temp-buffer
+            (when (zerop (call-process "global" nil (list t nil) nil "-pr"))
+              (file-name-as-directory
+               (comment-string-strip (buffer-string) t t)))))))
 
 (defun ggtags-check-root-directory ()
   (or (ggtags-root-directory) (error "File GTAGS not found")))
@@ -160,14 +153,13 @@ Return -1 if it does not exist."
       (if (yes-or-no-p "File GTAGS not found; run gtags? ")
           (let ((root (read-directory-name "Directory: " nil nil t)))
             (and (= (length root) 0) (error "No directory chosen"))
-            (ggtags-ignore-file-error
-              (with-temp-buffer
-                (if (zerop (let ((default-directory
-                                   (file-name-as-directory root)))
-                             (call-process "gtags" nil t)))
-                    (message "File GTAGS generated in `%s'"
-                             (ggtags-root-directory))
-                  (error "%s" (comment-string-strip (buffer-string) t t))))))
+            (with-temp-buffer
+              (if (zerop (let ((default-directory
+                                 (file-name-as-directory root)))
+                           (call-process "gtags" nil t)))
+                  (message "File GTAGS generated in `%s'"
+                           (ggtags-root-directory))
+                (error "%s" (comment-string-strip (buffer-string) t t)))))
         (error "Aborted"))))
 
 (defun ggtags-tag-names-1 (root &optional prefix)
@@ -488,15 +480,15 @@ When called with prefix, ask the name and kind of tag."
   "A function suitable for `imenu-create-index-function'."
   (when buffer-file-name
     (let ((file (file-truename buffer-file-name)))
-      (ggtags-ignore-file-error
-        (with-temp-buffer
-          (when (zerop (call-process "global" nil t nil "-f" file))
-            (goto-char (point-min))
-            (loop while (re-search-forward
-                         "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)" nil t)
-                  collect (list (match-string 1)
-                                (string-to-number (match-string 2))
-                                'ggtags-goto-imenu-index))))))))
+      (with-temp-buffer
+        (when (zerop (with-demoted-errors
+                       (call-process "global" nil t nil "-f" file)))
+          (goto-char (point-min))
+          (loop while (re-search-forward
+                       "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)" nil t)
+                collect (list (match-string 1)
+                              (string-to-number (match-string 2))
+                              'ggtags-goto-imenu-index)))))))
 
 ;;; hippie-expand
 

commit da32a6a4e9fd28006e4a53e99250e80587cb50bf
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 21 01:20:38 2013 +0400

    company-clang: Only initialize in supported major modes

diff --git a/NEWS.md b/NEWS.md
index 1e562ff..a14f605 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,8 @@
 
 ## Next
 
+* `company-clang` is now only initialized in supported buffers.
+  So, no error messages if you don't have Clang until you open a C file.
 * `company-clang` recognizes Clang included with recent Xcode.
 * New commands `company-select-previous-or-abort` and
   `company-select-next-or-abort`, bound to `<up>` and `<down>`.
diff --git a/company-clang.el b/company-clang.el
index 7c3a3b4..6b80ef0 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -222,10 +222,11 @@ Completions only work correctly when the buffer has been 
saved.
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-clang))
-    (init (unless company-clang-executable
-            (error "Company found no clang executable"))
-          (when (< (company-clang-version) company-clang-required-version)
-            (error "Company requires clang version 1.1")))
+    (init (when (memq major-mode company-clang-modes)
+            (unless company-clang-executable
+              (error "Company found no clang executable"))
+            (when (< (company-clang-version) company-clang-required-version)
+              (error "Company requires clang version 1.1"))))
     (prefix (and (memq major-mode company-clang-modes)
                  buffer-file-name
                  company-clang-executable

commit 38aa1ca2f88607c8cd9f9b5a14bf0dfadadc5546
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 21 01:04:27 2013 +0400

    Update NEWS

diff --git a/NEWS.md b/NEWS.md
index a4d0afe..1e562ff 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2,6 +2,7 @@
 
 ## Next
 
+* `company-clang` recognizes Clang included with recent Xcode.
 * New commands `company-select-previous-or-abort` and
   `company-select-next-or-abort`, bound to `<up>` and `<down>`.
 

commit 5b0f5b93f6982545561de5d7be19b3fc291a0814
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 20 23:46:43 2013 +0400

    company-clang: Update docstring

diff --git a/company-clang.el b/company-clang.el
index e239c61..7c3a3b4 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -210,8 +210,7 @@ Prefix files (-include ...) can be selected with
 
 (defun company-clang (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for clang.
-Clang is a parser for C and ObjC.  The unreleased development version of
-clang (1.1) is required.
+Clang is a parser for C and ObjC.  Clang version 1.1 or newer is required.
 
 Additional command line arguments can be specified in
 `company-clang-arguments'.  Prefix files (-include ...) can be selected

commit 3c666787bf15c85809ca0c4f3813169b819d3270
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 20 23:40:27 2013 +0400

    Fix #3

diff --git a/company-clang.el b/company-clang.el
index 966ef79..e239c61 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -181,16 +181,19 @@ Prefix files (-include ...) can be selected with
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defconst company-clang-required-version "1.1")
+(defconst company-clang-required-version 1.1)
 
 (defsubst company-clang-version ()
   "Return the version of `company-clang-executable'."
   (with-temp-buffer
     (call-process company-clang-executable nil t nil "--version")
     (goto-char (point-min))
-    (if (re-search-forward "clang version \\([0-9.]+\\)" nil t)
-        (match-string-no-properties 1)
-      "0")))
+    (if (re-search-forward "clang\\(?: version \\|-\\)\\([0-9.]+\\)" nil t)
+        (let ((ver (string-to-number (match-string-no-properties 1))))
+          (if (> ver 100)
+              (/ ver 100)
+            ver))
+      0)))
 
 (defun company-clang-objc-templatify (selector)
   (let* ((end (point))
@@ -222,8 +225,7 @@ Completions only work correctly when the buffer has been 
saved.
     (interactive (company-begin-backend 'company-clang))
     (init (unless company-clang-executable
             (error "Company found no clang executable"))
-          (when (version< (company-clang-version)
-                          company-clang-required-version)
+          (when (< (company-clang-version) company-clang-required-version)
             (error "Company requires clang version 1.1")))
     (prefix (and (memq major-mode company-clang-modes)
                  buffer-file-name

commit f18a8bc3004da4382bdcfdfa4cf515853b0d2e1b
Author: Leo Liu <address@hidden>
Date:   Wed Mar 20 19:52:12 2013 +0800

    Update README.rst

diff --git a/README.rst b/README.rst
index efe01d4..45d0cfa 100644
--- a/README.rst
+++ b/README.rst
@@ -3,8 +3,7 @@
 =========================
  
 A package for working with `GNU Global
-<http://www.gnu.org/software/global>`_ source tagging system inside
-Emacs.
+<http://www.gnu.org/software/global>`_ source tagging system in Emacs.
 
 This package is part of `GNU ELPA <http://elpa.gnu.org>`_
 (``M-x list-packages``).
@@ -20,6 +19,15 @@ Features
    features)
 #. Abbreviated display of file names
 
+Why GNU Global
+~~~~~~~~~~~~~~
+
+The opengrok project composed a feature comparison table between a few
+tools. The `page
+<http://hub.opensolaris.org/bin/view/Project+opengrok>`_ is taken
+offline after 2013-03-24 but `here <http://i.imgur.com/IQCPQ0j.png>`_
+is a backup.
+
 Screenshot
 ~~~~~~~~~~
 

commit acf66fb09d6bb44e00e789994fa0bb916213459a
Author: Leo Liu <address@hidden>
Date:   Wed Mar 20 19:09:51 2013 +0800

    Cache the value of function ggtags-root-directory

diff --git a/ggtags.el b/ggtags.el
index 59828c0..ea58b52 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -38,7 +38,13 @@
 (eval-when-compile
   (unless (fboundp 'setq-local)
     (defmacro setq-local (var val)
-      (list 'set (list 'make-local-variable (list 'quote var)) val))))
+      (list 'set (list 'make-local-variable (list 'quote var)) val)))
+
+  (unless (fboundp 'defvar-local)
+    (defmacro defvar-local (var val &optional docstring)
+      (declare (debug defvar) (doc-string 3))
+      (list 'progn (list 'defvar var val docstring)
+            (list 'make-variable-buffer-local (list 'quote var))))))
 
 (defgroup ggtags nil
   "GNU Global source code tagging system."
@@ -132,13 +138,19 @@ Return -1 if it does not exist."
   (> (ggtags-get-timestamp key)
      (or (fourth (ggtags-cache-get key)) 0)))
 
+(defvar-local ggtags-root-directory 'init
+  "Internal; use function `ggtags-root-directory' instead.")
+
 ;;;###autoload
 (defun ggtags-root-directory ()
-  (ggtags-ignore-file-error
-    (with-temp-buffer
-      (when (zerop (call-process "global" nil (list t nil) nil "-pr"))
-        (file-name-as-directory
-         (comment-string-strip (buffer-string) t t))))))
+  (if (string-or-null-p ggtags-root-directory)
+      ggtags-root-directory
+    (setq ggtags-root-directory
+          (ggtags-ignore-file-error
+           (with-temp-buffer
+             (when (zerop (call-process "global" nil (list t nil) nil "-pr"))
+               (file-name-as-directory
+                (comment-string-strip (buffer-string) t t))))))))
 
 (defun ggtags-check-root-directory ()
   (or (ggtags-root-directory) (error "File GTAGS not found")))

commit 48afb6016c87bd72ce6c14b1947b2c22a8827f66
Author: Leo Liu <address@hidden>
Date:   Wed Mar 20 19:00:29 2013 +0800

    New function try-complete-ggtags-tag for hippie-expand

diff --git a/ggtags.el b/ggtags.el
index 20600bf..59828c0 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -463,6 +463,7 @@ When called with prefix, ask the name and kind of tag."
     (setq ggtags-tag-overlay nil)))
 
 ;;; imenu
+
 (defun ggtags-goto-imenu-index (name line &rest _args)
   (save-restriction
     (widen)
@@ -485,5 +486,30 @@ When called with prefix, ask the name and kind of tag."
                                 (string-to-number (match-string 2))
                                 'ggtags-goto-imenu-index))))))))
 
+;;; hippie-expand
+
+;;;###autoload
+(defun try-complete-ggtags-tag (old)
+  "A function suitable for `hippie-expand-try-functions-list'."
+  (with-no-warnings                     ; to avoid loading hippie-exp
+    (unless old
+      (he-init-string (if (looking-back "\\_<.*" (line-beginning-position))
+                          (match-beginning 0)
+                        (point))
+                      (point))
+      (setq he-expand-list
+            (and (not (equal he-search-string ""))
+                 (ggtags-root-directory)
+                 (sort (all-completions he-search-string
+                                        (ggtags-tag-names))
+                       'string-lessp))))
+    (if (null he-expand-list)
+        (progn
+          (if old (he-reset-string))
+          nil)
+      (he-substitute-string (car he-expand-list))
+      (setq he-expand-list (cdr he-expand-list))
+      t)))
+
 (provide 'ggtags)
 ;;; ggtags.el ends here

commit dd7ce94b2bb4a8967cd442c601cb4bcb765306a8
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 20 10:35:15 2013 +0400

    company-pseudo-tooltip-show: No need to set overlay window here

diff --git a/company.el b/company.el
index 2d2aead..df758e1 100644
--- a/company.el
+++ b/company.el
@@ -1752,8 +1752,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
                             args))
 
         (overlay-put ov 'company-column column)
-        (overlay-put ov 'company-height (abs height))
-        (overlay-put ov 'window (selected-window))))))
+        (overlay-put ov 'company-height (abs height))))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (company--col-row pos)))

commit 1e34bac4cc864071284c40b7a0d06cc4b039890b
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 20 09:18:02 2013 +0400

    Add new commands: `company-select-{previous,next}-or-abort`

diff --git a/NEWS.md b/NEWS.md
index bca1d9e..a4d0afe 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,10 @@
 # History of user-visible changes
 
+## Next
+
+* New commands `company-select-previous-or-abort` and
+  `company-select-next-or-abort`, bound to `<up>` and `<down>`.
+
 ## 2013-03-19 (0.6)
 
 * Across-the-board bugfixing.
diff --git a/company.el b/company.el
index 8b097b3..2d2aead 100644
--- a/company.el
+++ b/company.el
@@ -458,8 +458,8 @@ The work-around consists of adding a newline.")
     (define-key keymap "\C-g" 'company-abort)
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
-    (define-key keymap (kbd "<down>") 'company-select-next)
-    (define-key keymap (kbd "<up>") 'company-select-previous)
+    (define-key keymap (kbd "<down>") 'company-select-next-or-abort)
+    (define-key keymap (kbd "<up>") 'company-select-previous-or-abort)
     (define-key keymap [down-mouse-1] 'ignore)
     (define-key keymap [down-mouse-3] 'ignore)
     (define-key keymap [mouse-1] 'company-complete-mouse)
@@ -1191,9 +1191,7 @@ can retrieve meta-data for them."
   (interactive)
   (company-search-assert-enabled)
   (company-search-mode 0)
-  (when last-input-event
-    (clear-this-command-keys t)
-    (setq unread-command-events (list last-input-event))))
+  (company--unread-last-input))
 
 (defvar company-search-map
   (let ((i 0)
@@ -1202,7 +1200,7 @@ can retrieve meta-data for them."
         (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
                               'company-search-printing-char)
       (with-no-warnings
-        ;; obselete in Emacs 23
+        ;; obsolete in Emacs 23
         (let ((l (generic-character-list))
               (table (nth 1 keymap)))
           (while l
@@ -1297,6 +1295,24 @@ followed by `company-search-kill-others' after each 
input."
   (when (company-manual-begin)
     (company-set-selection (1- company-selection))))
 
+(defun company-select-next-or-abort ()
+  "Select the next candidate if more than one, else abort
+and invoke the normal binding."
+  (interactive)
+  (if (> company-candidates-length 1)
+      (company-select-next)
+    (company-abort)
+    (company--unread-last-input)))
+
+(defun company-select-previous-or-abort ()
+  "Select the previous candidate if more than one, else abort
+and invoke the normal binding."
+  (interactive)
+  (if (> company-candidates-length 1)
+      (company-select-previous)
+    (company-abort)
+    (company--unread-last-input)))
+
 (defun company-select-mouse (event)
   "Select the candidate picked by the mouse."
   (interactive "e")
@@ -1415,9 +1431,12 @@ To show the number next to the candidates in some 
back-ends, enable
          (while (memq (setq cmd (key-binding (vector (list (read-event)))))
                       company--electric-commands)
            (call-interactively cmd))
-         (when last-input-event
-           (clear-this-command-keys t)
-           (setq unread-command-events (list last-input-event)))))))
+         (company--unread-last-input)))))
+
+(defun company--unread-last-input ()
+  (when last-input-event
+    (clear-this-command-keys t)
+    (setq unread-command-events (list last-input-event))))
 
 (defun company-show-doc-buffer ()
   "Temporarily show a buffer with the complete documentation for the 
selection."

commit dae36cc520cf60960d0d650ff09c09ecf5525d3a
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 20 08:55:19 2013 +0400

    Extract NEWS.md
    
    * Reorder 0.6's entries in reverse chronological order, like in other 
versions.

diff --git a/.dir-locals.el b/.dir-locals.el
index a4fea85..3a4c010 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,2 +1,3 @@
 ((nil . ((indent-tabs-mode . nil)
-         (fill-column . 80))))
+         (fill-column . 80)
+         (sentence-end-double-space . t))))
diff --git a/NEWS.md b/NEWS.md
new file mode 100644
index 0000000..bca1d9e
--- /dev/null
+++ b/NEWS.md
@@ -0,0 +1,101 @@
+# History of user-visible changes
+
+## 2013-03-19 (0.6)
+
+* Across-the-board bugfixing.
+* `company-pysmell` is not used by default anymore.
+* Loading of `nxml`, `semantic`, `pymacs` and `ropemacs` is now deferred.
+* Candidates from grouped back-ends are merged more conservatively: only
+  back-ends that return the same prefix at point are used.
+* `company-clang` now shows meta information, too.
+* Some performance improvements.
+* Fixed two old tooltip annoyances.
+* Instead of `overrriding-terminal-local-map`, we're now using
+  `emulation-mode-map-alists` (experimental).  This largely means that when the
+  completion keymap is active, other minor modes' keymaps are still used, so,
+  for example, it's not as easy to accidentally circumvent `paredit-mode`
+  when it's enabled.
+* `company-elisp` has seen some improvements.
+* Added `company-capf`: completion adapter using
+  `completion-at-point-functions`.  (Stefan Monnier)
+* Clang completions now include macros and are case-sensitive.
+* Switching between tag files now works correctly with `company-etags`.
+
+## 2010-02-24 (0.5)
+
+* `company-ropemacs` now provides location and docs.  (Fernando H. Silva)
+* Added `company-with-candidate-inserted` macro.
+* Added `company-clang` back-end.
+* Added new mechanism for non-consecutive insertion.
+  (So far only used by clang for ObjC.)
+* The semantic back-end now shows meta information for local symbols.
+* Added compatibility for CEDET in Emacs 23.2 and from CVS.  (Oleg Andreev)
+
+## 2009-05-07 (0.4.3)
+
+* Added `company-other-backend`.
+* Idle completion no longer interrupts multi-key command input.
+* Added `company-ropemacs` and `company-pysmell` back-ends.
+
+## 2009-04-25 (0.4.2)
+
+* In C modes . and -> now count towards `company-minimum-prefix-length`.
+* Reverted default front-end back to `company-preview-if-just-one-frontend`.
+* The pseudo tooltip will no longer be clipped at the right window edge.
+* Added `company-tooltip-minimum`.
+* Windows compatibility fixes.
+
+## 2009-04-19 (0.4.1)
+
+* Added `global-company-mode`.
+* Performance enhancements.
+* Added `company-eclim` back-end.
+* Added safer workaround for Emacs `posn-col-row` bug.
+
+## 2009-04-18 (0.4)
+
+* Automatic completion is now aborted if the prefix gets too short.
+* Added option `company-dabbrev-time-limit`.
+* `company-backends` now supports merging back-ends.
+* Added back-end `company-dabbrev-code` for generic code.
+* Fixed `company-begin-with`.
+
+## 2009-04-15 (0.3.1)
+
+* Added 'stop prefix to prevent dabbrev from completing inside of symbols.
+* Fixed issues with tabbar-mode and line-spacing.
+* Performance enhancements.
+
+## 2009-04-12 (0.3)
+
+* Added `company-begin-commands` option.
+* Added abbrev, tempo and Xcode back-ends.
+* Back-ends are now interactive.  You can start them with M-x backend-name.
+* Added `company-begin-with` for starting company from elisp-code.
+* Added hooks.
+* Added `company-require-match` and `company-auto-complete` options.
+
+## 2009-04-05 (0.2.1)
+
+* Improved Emacs Lisp back-end behavior for local variables.
+* Added `company-elisp-detect-function-context` option.
+* The mouse can now be used for selection.
+
+## 2009-03-22 (0.2)
+
+* Added `company-show-location`.
+* Added etags back-end.
+* Added work-around for end-of-buffer bug.
+* Added `company-filter-candidates`.
+* More local Lisp variables are now included in the candidates.
+
+## 2009-03-21 (0.1.5)
+
+* Fixed elisp documentation buffer always showing the same doc.
+* Added `company-echo-strip-common-frontend`.
+* Added `company-show-numbers` option and M-0 ... M-9 default bindings.
+* Don't hide the echo message if it isn't shown.
+
+## 2009-03-20 (0.1)
+
+* Initial release.
diff --git a/company.el b/company.el
index 59ddcc6..8b097b3 100644
--- a/company.el
+++ b/company.el
@@ -65,93 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
-;; 2013-03-19 (0.6)
-;;    Switching between tag files now works correctly with `company-etags'.
-;;    Clang completions now include macros and are case-sensitive.
-;;    Added `company-capf': completion adapter using
-;;    `completion-at-point-functions'.  (Stefan Monnier)
-;;    `company-elisp' has some improvements.
-;;    Instead of `overrriding-terminal-local-map', we're now using
-;;    `emulation-mode-map-alists' (experimental).  This largely means that when
-;;    the completion keymap is active, other minor modes' keymaps are still
-;;    used, so, for example, it's not as easy to circumvent `paredit-mode'
-;;    accidentally when it's enabled.
-;;    Fixed two old tooltip annoyances.
-;;    Some performance improvements.
-;;    `company-clang' now shows meta information, too.
-;;    Candidates from grouped back-ends are merged more conservatively: only
-;;    back-ends that return the same prefix at point are used.
-;;    Loading of `nxml', `semantic', `pymacs' and `ropemacs' is now deferred.
-;;    `company-pysmell' is not used by default anymore.
-;;    Across-the-board bugfixing.
-;;
-;; 2010-02-24 (0.5)
-;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
-;;    Added `company-with-candidate-inserted' macro.
-;;    Added `company-clang' back-end.
-;;    Added new mechanism for non-consecutive insertion.
-;;      (So far only used by clang for ObjC.)
-;;    The semantic back-end now shows meta information for local symbols.
-;;    Added compatibility for CEDET in Emacs 23.2 and from CVS.  (Oleg Andreev)
-;;
-;; 2009-05-07 (0.4.3)
-;;    Added `company-other-backend'.
-;;    Idle completion no longer interrupts multi-key command input.
-;;    Added `company-ropemacs' and `company-pysmell' back-ends.
-;;
-;; 2009-04-25 (0.4.2)
-;;    In C modes . and -> now count towards `company-minimum-prefix-length'.
-;;    Reverted default front-end back to 
`company-preview-if-just-one-frontend'.
-;;    The pseudo tooltip will no longer be clipped at the right window edge.
-;;    Added `company-tooltip-minimum'.
-;;    Windows compatibility fixes.
-;;
-;; 2009-04-19 (0.4.1)
-;;    Added `global-company-mode'.
-;;    Performance enhancements.
-;;    Added `company-eclim' back-end.
-;;    Added safer workaround for Emacs `posn-col-row' bug.
-;;
-;; 2009-04-18 (0.4)
-;;    Automatic completion is now aborted if the prefix gets too short.
-;;    Added option `company-dabbrev-time-limit'.
-;;    `company-backends' now supports merging back-ends.
-;;    Added back-end `company-dabbrev-code' for generic code.
-;;    Fixed `company-begin-with'.
-;;
-;; 2009-04-15 (0.3.1)
-;;    Added 'stop prefix to prevent dabbrev from completing inside of symbols.
-;;    Fixed issues with tabbar-mode and line-spacing.
-;;    Performance enhancements.
-;;
-;; 2009-04-12 (0.3)
-;;    Added `company-begin-commands' option.
-;;    Added abbrev, tempo and Xcode back-ends.
-;;    Back-ends are now interactive.  You can start them with M-x backend-name.
-;;    Added `company-begin-with' for starting company from elisp-code.
-;;    Added hooks.
-;;    Added `company-require-match' and `company-auto-complete' options.
-;;
-;; 2009-04-05 (0.2.1)
-;;    Improved Emacs Lisp back-end behavior for local variables.
-;;    Added `company-elisp-detect-function-context' option.
-;;    The mouse can now be used for selection.
-;;
-;; 2009-03-22 (0.2)
-;;    Added `company-show-location'.
-;;    Added etags back-end.
-;;    Added work-around for end-of-buffer bug.
-;;    Added `company-filter-candidates'.
-;;    More local Lisp variables are now included in the candidates.
-;;
-;; 2009-03-21 (0.1.5)
-;;    Fixed elisp documentation buffer always showing the same doc.
-;;    Added `company-echo-strip-common-frontend'.
-;;    Added `company-show-numbers' option and M-0 ... M-9 default bindings.
-;;    Don't hide the echo message if it isn't shown.
-;;
-;; 2009-03-20 (0.1)
-;;    Initial release.
+;; See NEWS.md in the repository.
 
 ;;; Code:
 

commit 72fbcfaba1f40b692845a38d9c3c36d8338de59a
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 18:46:51 2013 +0400

    Update summary string

diff --git a/company.el b/company.el
index 8f1e711..59ddcc6 100644
--- a/company.el
+++ b/company.el
@@ -1,4 +1,4 @@
-;;; company.el --- Extensible inline text completion mechanism
+;;; company.el --- Modular in-buffer completion framework
 
 ;; Copyright (C) 2009-2013  Free Software Foundation, Inc.
 

commit 1925479b9f782bbe339e7f9e80653cecd6f12f2f
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 18:12:18 2013 +0400

    company-tests: add copyright boilerplate

diff --git a/company-tests.el b/company-tests.el
index bb1e654..1f5db14 100644
--- a/company-tests.el
+++ b/company-tests.el
@@ -1,3 +1,30 @@
+;;; company-tests.el --- company-mode tests
+
+;; Copyright (C) 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
+
 (require 'ert)
 (require 'company)
 (require 'company-keywords)

commit fecb101033b11233cb3eb0a2b288665f5c1ff1d1
Author: Leo Liu <address@hidden>
Date:   Tue Mar 19 18:54:22 2013 +0800

    (sit-for 0) to allow compilation-auto-jump in timer to run
    
    See http://debbugs.gnu.org/13829 for more info.

diff --git a/ggtags.el b/ggtags.el
index 601f466..20600bf 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.6
+;; Version: 0.6.1
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -287,6 +287,7 @@ When called with prefix, ask the name and kind of tag."
                    (point) 'compilation-message))))
     (ggtags-navigation-mode -1)
     ;; 0.5s delay for `ggtags-auto-jump-to-first-match'
+    (sit-for 0)                    ; See: http://debbugs.gnu.org/13829
     (ggtags-navigation-mode-cleanup buf 0.5)))
 
 (define-compilation-mode ggtags-global-mode "Global"
@@ -338,8 +339,7 @@ When called with prefix, ask the name and kind of tag."
            (when (and (derived-mode-p 'ggtags-global-mode)
                       (get-buffer-window))
              (delete-window (get-buffer-window)))
-           (and time (run-with-idle-timer time nil
-                                          'kill-buffer (current-buffer)))))))
+           (and time (run-with-idle-timer time nil 'kill-buffer buf))))))
 
 (defun ggtags-navigation-mode-done ()
   (interactive)

commit 72a824ffdf93287d72a0479a6a210ad0af46724a
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 07:38:07 2013 +0400

    Release 0.6

diff --git a/company.el b/company.el
index b692c40..8f1e711 100644
--- a/company.el
+++ b/company.el
@@ -3,9 +3,10 @@
 ;; Copyright (C) 2009-2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
-;; Version: 0.5
+;; Maintainer: Dmitry Gutov <address@hidden>
+;; Version: 0.6
 ;; Keywords: abbrev, convenience, matching
-;; URL: http://nschum.de/src/emacs/company-mode/
+;; URL: http://company-mode.github.com/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
 
 ;; This file is part of GNU Emacs.
@@ -64,7 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
-;;    Switching tags now works correctly in `company-etags'.
+;; 2013-03-19 (0.6)
+;;    Switching between tag files now works correctly with `company-etags'.
 ;;    Clang completions now include macros and are case-sensitive.
 ;;    Added `company-capf': completion adapter using
 ;;    `completion-at-point-functions'.  (Stefan Monnier)
@@ -81,6 +83,7 @@
 ;;    back-ends that return the same prefix at point are used.
 ;;    Loading of `nxml', `semantic', `pymacs' and `ropemacs' is now deferred.
 ;;    `company-pysmell' is not used by default anymore.
+;;    Across-the-board bugfixing.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)

commit c2fcc867f9014315646f0641069cdd3b614a8bc2
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 07:29:04 2013 +0400

    Fix typo: pysmell -> pymacs

diff --git a/company.el b/company.el
index 106422f..b692c40 100644
--- a/company.el
+++ b/company.el
@@ -79,7 +79,7 @@
 ;;    `company-clang' now shows meta information, too.
 ;;    Candidates from grouped back-ends are merged more conservatively: only
 ;;    back-ends that return the same prefix at point are used.
-;;    Loading of `nxml', `semantic', `pysmell' and `ropemacs' is now deferred.
+;;    Loading of `nxml', `semantic', `pymacs' and `ropemacs' is now deferred.
 ;;    `company-pysmell' is not used by default anymore.
 ;;
 ;; 2010-02-24 (0.5)

commit ab9d10a7fc525a4ffcf3c90b218484c4fc7089bd
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 07:05:46 2013 +0400

    Fix company-echo-frontend

diff --git a/company.el b/company.el
index cfd0420..106422f 100644
--- a/company.el
+++ b/company.el
@@ -1934,6 +1934,10 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defvar company-echo-last-msg nil)
 (make-variable-buffer-local 'company-echo-last-msg)
 
+(defvar company-echo-timer nil)
+
+(defvar company-echo-delay .01)
+
 (defun company-echo-show (&optional getter)
   (when getter
     (setq company-echo-last-msg (funcall getter)))

commit 65a07086a81663b372c8589da4a966fa672956e7
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 06:51:34 2013 +0400

    Phrasing

diff --git a/company.el b/company.el
index 06f2d3f..cfd0420 100644
--- a/company.el
+++ b/company.el
@@ -29,7 +29,7 @@
 ;; candidates are called back-ends, modules for displaying them are front-ends.
 ;;
 ;; Company comes with many back-ends, e.g. `company-elisp'.  These are
-;; distributed in individual files and can be used individually.
+;; distributed in separate files and can be used individually.
 ;;
 ;; Place company.el and the back-ends you want to use in a directory and add 
the
 ;; following to your .emacs:

commit 32b8bc35f054b315f8ff2bffc6489589c43d5964
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 06:50:23 2013 +0400

    company-backends: remove 'company-pysmell

diff --git a/company.el b/company.el
index d2bf000..06f2d3f 100644
--- a/company.el
+++ b/company.el
@@ -79,6 +79,8 @@
 ;;    `company-clang' now shows meta information, too.
 ;;    Candidates from grouped back-ends are merged more conservatively: only
 ;;    back-ends that return the same prefix at point are used.
+;;    Loading of `nxml', `semantic', `pysmell' and `ropemacs' is now deferred.
+;;    `company-pysmell' is not used by default anymore.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
@@ -348,7 +350,7 @@ Requires Emacs 24.1 or newer."
                               company-clang company-semantic company-eclim
                               company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
-                               company-pysmell company-keywords)
+                               company-keywords)
                               company-oddmuse company-files company-dabbrev)
   "The list of active back-ends (completion engines).
 Each list elements can itself be a list of back-ends.  In that case their

commit ecf7af6c22f3ba8bd189ebb3b3f86d1bb85f7441
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 06:27:36 2013 +0400

    company-ropemacs: defer loading pymacs and ropemacs

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 8c54d51..bba9bcb 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -28,13 +28,6 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl))
-(require 'pymacs)
-
-(unless (fboundp 'rope-completions)
-  (pymacs-load "ropemacs" "rope-"))
-
-(unless (fboundp 'rope-completions)
-  (error "rope-completions not found, try development version of ropemacs"))
 
 (defun company-ropemacs--grab-symbol ()
   (let ((symbol (company-grab-symbol)))
@@ -67,6 +60,10 @@
   "A `company-mode' completion back-end for ropemacs."
   (interactive (list 'interactive))
   (case command
+    (init (when (and (derived-mode-p 'python-mode)
+                     (not (fboundp 'rope-completions)))
+            (require 'pymacs)
+            (pymacs-load "ropemacs" "rope-")))
     (interactive (company-begin-backend 'company-ropemacs))
     (prefix (and (derived-mode-p 'python-mode)
                  (not (company-in-string-or-comment))

commit 78d6ef179eeec28502ff821f2a28d7ba641adebc
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 06:09:07 2013 +0400

    company--pseudo-tooltip-height: account for wrapped lines

diff --git a/company.el b/company.el
index 13b0db4..d2bf000 100644
--- a/company.el
+++ b/company.el
@@ -1776,7 +1776,7 @@ Example:
 (defsubst company--pseudo-tooltip-height ()
   "Calculate the appropriate tooltip height.
 Returns a negative number if the tooltip should be displayed above point."
-  (let* ((lines (count-lines (window-start) (point-at-bol)))
+  (let* ((lines (company--row))
          (below (- (company--window-inner-height) 1 lines)))
     (if (and (< below (min company-tooltip-minimum company-candidates-length))
              (> lines below))

commit 7a195c6bb28b93a12a73a51c445e35cd017f2c68
Author: Leo Liu <address@hidden>
Date:   Tue Mar 19 08:25:39 2013 +0800

    ack-mode-display-match has been merged upstream
    
    as compilation-display-error.

diff --git a/ack.el b/ack.el
index e6cab60..12b8815 100644
--- a/ack.el
+++ b/ack.el
@@ -217,17 +217,19 @@ This gets tacked on the end of the generated 
expressions.")
                         (match-string 1 file)
                       file))))))
 
-(defun ack-mode-display-match ()
-  "Display in another window the match in current line."
-  (interactive)
-  (setq compilation-current-error (point))
-  (next-error-no-select 0))
-
 (define-compilation-mode ack-mode "Ack"
   "A compilation mode tailored for ack."
   (setq-local compilation-disable-input t)
   (setq-local compilation-error-face 'compilation-info)
-  (add-hook 'compilation-filter-hook 'ack-filter nil t)
+  (add-hook 'compilation-filter-hook 'ack-filter nil t))
+
+;;; `compilation-display-error' is introduced in 24.4
+(unless (fboundp 'compilation-display-error)
+  (defun ack-mode-display-match ()
+    "Display in another window the match in current line."
+    (interactive)
+    (setq compilation-current-error (point))
+    (next-error-no-select 0))
   (define-key ack-mode-map "\C-o" #'ack-mode-display-match))
 
 (defun ack-skel-file ()

commit 9f69658a364991b0bbae940eb388dcc452aaa8c6
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 04:23:25 2013 +0400

    Phrasing

diff --git a/company.el b/company.el
index 5ccee5f..13b0db4 100644
--- a/company.el
+++ b/company.el
@@ -53,10 +53,9 @@
 ;;     (candidates (list "foobar" "foobaz" "foobarbaz"))
 ;;     (meta (format "This value is named %s" arg))))
 ;;
-;; Sometimes it is a good idea to mix two back-ends together, for example to
-;; enrich gtags with dabbrev-code results (to emulate local variables):
-;; To do this, add a list with the merged back-ends as an element in
-;; company-backends.
+;; Sometimes it is a good idea to mix several back-ends together, for example 
to
+;; enrich gtags with dabbrev-code results (to emulate local variables).
+;; To do this, add a list with both back-ends as an element in 
company-backends.
 ;;
 ;; Known Issues:
 ;; When point is at the very end of the buffer, the pseudo-tooltip appears very

commit 6009938d5bf83ea53e59831feaec5af549d0d0ac
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 04:19:11 2013 +0400

    company-dabbrev-code: use case-fold-search
    
    e7c7ba09d9b0bd859b0561009be5eab5020593ed was only half right.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 64f60c7..b98c17d 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -78,7 +78,7 @@ comments or strings."
                      (apply 'derived-mode-p company-dabbrev-code-modes))
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))
-    (candidates (let ((completion-ignore-case nil))
+    (candidates (let ((case-fold-search nil))
                   (company-dabbrev--search
                    (company-dabbrev-code--make-regexp arg)
                    company-dabbrev-code-time-limit

commit 52a81628a9646f9aba03528b26efc5c6cb4a08f2
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 03:46:02 2013 +0400

    company-eclim: reorder commentary text

diff --git a/company-eclim.el b/company-eclim.el
index 592e345..e5bce3b 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -21,12 +21,12 @@
 
 ;;; Commentary:
 ;;
+;; Eclim version 1.7.13 or newer (?) is required.
+;;
 ;; This completion backend is pretty barebone.
 ;;
 ;; `emacs-eclim' provides an alternative backend, and it also allows you to
-;; actually control Eclim from Emacs. Check it out.
-;;
-;; Eclim version 1.7.13 or newer (?) is required.
+;; actually control Eclim from Emacs.
 
 ;;; Code:
 

commit d79c8d053db68cff5d718b64e44b0b31d9d4b948
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 01:00:03 2013 +0400

    company--multi-backend-adapter: use cl-loop and nconc

diff --git a/company.el b/company.el
index 3c4e55e..5ccee5f 100644
--- a/company.el
+++ b/company.el
@@ -733,11 +733,10 @@ keymap during active completions (`company-active-map'):
                              backends)))
     (case command
       (candidates
-       (apply 'append (mapcar (lambda (backend)
-                                (when (equal (funcall backend 'prefix)
-                                             (car args))
-                                  (apply backend 'candidates args)))
-                              backends)))
+       (loop for backend in backends
+             when (equal (funcall backend 'prefix)
+                         (car args))
+             nconc (apply backend 'candidates args)))
       (sorted nil)
       (duplicates t)
       (otherwise

commit 06270357092d267fd65e501a37a15e2f5e306e92
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 19 00:45:23 2013 +0400

    company--multi-backend-adapter: only use candidates from back-ends with the 
same prefix

diff --git a/company.el b/company.el
index 081b3bf..3c4e55e 100644
--- a/company.el
+++ b/company.el
@@ -78,6 +78,8 @@
 ;;    Fixed two old tooltip annoyances.
 ;;    Some performance improvements.
 ;;    `company-clang' now shows meta information, too.
+;;    Candidates from grouped back-ends are merged more conservatively: only
+;;    back-ends that return the same prefix at point are used.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
@@ -731,7 +733,10 @@ keymap during active completions (`company-active-map'):
                              backends)))
     (case command
       (candidates
-       (apply 'append (mapcar (lambda (backend) (apply backend command args))
+       (apply 'append (mapcar (lambda (backend)
+                                (when (equal (funcall backend 'prefix)
+                                             (car args))
+                                  (apply backend 'candidates args)))
                               backends)))
       (sorted nil)
       (duplicates t)

commit 408c2e07e8064a5e6d7486ecafd19b2ee8a9ac7b
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 19:36:37 2013 +0400

    company-pysmell: update the commentary
    
    Pysmell hasn't been updated in 4 years, there's no reason why the back-end
    would stop working.

diff --git a/company-pysmell.el b/company-pysmell.el
index 8ee889a..fe36eef 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -22,7 +22,8 @@
 
 ;;; Commentary:
 ;;
-;; Someone who can actually install Pysmell should tell us if this still works.
+;; The main problem with using this backend is installing Pysmell.
+;; I couldn't manage to do that. --Dmitry
 
 ;;; Code:
 

commit d5f74fe53238d8dbf55dc8450b27b491861dc74d
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Mar 18 11:59:00 2013 +0100

    * eldoc-eval.el: only need to inline 
eldoc-display-message-no-interference-p and set eldoc-message-function to 
'message.
    Fix recursive minibuffers: Don't send eldoc info of current-buffer.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index cede787..dbc142e 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -61,37 +61,7 @@ Should take one arg: the string to display"
 ;; minibuffer is in use, disable this and inline old Emacs behavior.
 
 (when (boundp 'eldoc-message-function)
-  (setq eldoc-message-function nil)
-
-  (defun eldoc-message (&rest args)
-    (let ((omessage eldoc-last-message))
-      (setq eldoc-last-message
-            (cond ((eq (car args) eldoc-last-message) eldoc-last-message)
-                  ((null (car args)) nil)
-                  ;; If only one arg, no formatting to do, so put it in
-                  ;; eldoc-last-message so eq test above might succeed on
-                  ;; subsequent calls.
-                  ((null (cdr args)) (car args))
-                  (t (apply 'format args))))
-      ;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages
-      ;; are recorded in a log.  Do not put eldoc messages in that log since
-      ;; they are Legion.
-      ;; Emacs way of preventing log messages.
-      (let ((message-log-max nil))
-        (cond (eldoc-last-message (message "%s" eldoc-last-message))
-              (omessage (message nil)))))
-    eldoc-last-message)
-
-  (defun eldoc-display-message-p ()
-    (and (eldoc-display-message-no-interference-p)
-         ;; If this-command is non-nil while running via an idle
-         ;; timer, we're still in the middle of executing a command,
-         ;; e.g. a query-replace where it would be annoying to
-         ;; overwrite the echo area.
-         (and (not this-command)
-              (symbolp last-command)
-              (intern-soft (symbol-name last-command)
-                           eldoc-message-commands))))
+  (setq eldoc-message-function 'message)
 
   (defun eldoc-display-message-no-interference-p ()
     (and eldoc-mode
@@ -175,27 +145,26 @@ See `with-eldoc-in-minibuffer'."
 
 (defun eldoc-mode-in-minibuffer ()
   "Show eldoc for current minibuffer input."
-  (let ((buf (with-selected-window (minibuffer-window)
-               (buffer-name))))
+  (let ((buf (buffer-name (window-buffer (active-minibuffer-window)))))
     ;; If this minibuffer have been started with
     ;;`with-eldoc-in-minibuffer' give it eldoc support
     ;; and update mode-line, otherwise do nothing.
     (condition-case err
         (when (member buf eldoc-active-minibuffers-list)
-          (let* ((str-all (with-current-buffer buf
-                            (minibuffer-completion-contents)))
-                 (sym     (when str-all
-                            (with-temp-buffer
-                              (insert str-all)
-                              (goto-char (point-max))
-                              (unless (looking-back ")\\|\"")
-                                (forward-char -1))
-                              (eldoc-current-symbol))))
-                 (info-fn (eldoc-fnsym-in-current-sexp))
-                 (doc     (or (eldoc-get-var-docstring sym)
-                              (eldoc-get-fnsym-args-string
-                               (car info-fn) (cadr info-fn)))))
-            (when doc (funcall eldoc-in-minibuffer-show-fn doc))))
+          (with-current-buffer buf
+            (let* ((str-all (minibuffer-completion-contents))
+                   (sym     (when str-all
+                              (with-temp-buffer
+                                (insert str-all)
+                                (goto-char (point-max))
+                                (unless (looking-back ")\\|\"")
+                                  (forward-char -1))
+                                (eldoc-current-symbol))))
+                   (info-fn (eldoc-fnsym-in-current-sexp))
+                   (doc     (or (eldoc-get-var-docstring sym)
+                                (eldoc-get-fnsym-args-string
+                                 (car info-fn) (cadr info-fn)))))
+              (when doc (funcall eldoc-in-minibuffer-show-fn doc)))))
       (scan-error nil)
       (beginning-of-buffer nil)
       (error (message "Eldoc in minibuffer error: %S" err)))))

commit c0fefbb2b457a87c271fdd3a91d907f15d8c1d21
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 09:38:04 2013 +0400

    company-keywords: fix interactive invocation

diff --git a/company-keywords.el b/company-keywords.el
index 20bd7b0..75d37d6 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -219,7 +219,7 @@
   "A `company-mode' back-end for programming language keywords."
   (interactive (list 'interactive))
   (case command
-    (interactive (company-begin-backend 'company-))
+    (interactive (company-begin-backend 'company-keywords))
     (prefix (and (assq major-mode company-keywords-alist)
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))

commit 3b953efb9a7071f7dfb34906247e2a8e554fbb45
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 09:13:55 2013 +0400

    company-nxml: don't load nxml ourselves

diff --git a/company-nxml.el b/company-nxml.el
index 0be1819..33d6f7b 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -1,6 +1,6 @@
 ;;; company-nxml.el --- A company-mode completion back-end for nxml-mode
 
-;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -26,10 +26,19 @@
 ;;; Code:
 
 (require 'company)
-(require 'nxml-mode)
-(require 'rng-nxml)
 (eval-when-compile (require 'cl))
 
+(defvar rng-open-elements)
+(defvar rng-validate-mode)
+(defvar rng-in-attribute-regex)
+(defvar rng-in-attribute-value-regex)
+(declare-function rng-set-state-after "rng-nxml")
+(declare-function rng-match-possible-start-tag-names "rng-match")
+(declare-function rng-adjust-state-for-attribute "rng-nxml")
+(declare-function rng-match-possible-attribute-names "rng-match")
+(declare-function rng-adjust-state-for-attribute-value "rng-nxml")
+(declare-function rng-match-possible-value-strings "rng-match")
+
 (defconst company-nxml-token-regexp
   "\\(?:[_[:alpha:]][-._[:alnum:]]*\\_>\\)")
 

commit 48ecab18628772451b8870fdc5ac4587cd7be3ba
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 09:02:24 2013 +0400

    company-files: insert slash when appropriate

diff --git a/company-files.el b/company-files.el
index 6b34d57..ebb11c0 100644
--- a/company-files.el
+++ b/company-files.el
@@ -1,6 +1,6 @@
 ;;; company-files.el --- A company-mode completion back-end for file names
 
-;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -67,7 +67,9 @@
         (when (file-directory-p file)
           ;; Add one level of children.
           (dolist (child (company-files-directory-files file ""))
-            (push (concat file child) candidates))))
+            (push (concat file
+                          (unless (eq (aref file (1- (length file))) ?/) "/")
+                          child) candidates))))
       (setq company-files-completion-cache (cons dir (nreverse candidates))))
     (cdr company-files-completion-cache)))
 

commit f2c4167c3371da3632fc264a6fd111d9be4ffaf4
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 08:43:22 2013 +0400

    company-etags: not always sorted

diff --git a/company-etags.el b/company-etags.el
index 508aac8..88b9fca 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -79,8 +79,7 @@ buffer automatically."
                 (when (fboundp 'find-tag-noselect)
                   (save-excursion
                     (let ((buffer (find-tag-noselect arg)))
-                      (cons buffer (with-current-buffer buffer (point))))))))
-    (sorted t)))
+                      (cons buffer (with-current-buffer buffer (point))))))))))
 
 (provide 'company-etags)
 ;;; company-etags.el ends here

commit a2cdaf107a29ad6c23ba24ad60c09411b4e06a9e
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 08:24:42 2013 +0400

    company-pysmell: add a note

diff --git a/company-pysmell.el b/company-pysmell.el
index 8cfe10d..8ee889a 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -22,6 +22,7 @@
 
 ;;; Commentary:
 ;;
+;; Someone who can actually install Pysmell should tell us if this still works.
 
 ;;; Code:
 

commit 6ffcecc4be2d87a0cd9d061937cbd6083aa99666
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 07:59:22 2013 +0400

    company-ropemacs: describe dependencies

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 2b402f7..8c54d51 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,6 +1,6 @@
 ;;; company-ropemacs.el --- A company-mode completion back-end for pysmell.el
 
-;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -22,6 +22,8 @@
 
 ;;; Commentary:
 ;;
+;; Requires pymacs Emacs package (you can get it from Marmalade),
+;; and on Python side: pymacs, rope, ropemacs and ropemode.
 
 ;;; Code:
 

commit f923ea8dc00419742ddd2745c5ef3b5d0c20da07
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 07:11:00 2013 +0400

    company-eclim: Update to new communication protocol

diff --git a/company-eclim.el b/company-eclim.el
index db486c1..592e345 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,6 +1,6 @@
 ;;; company-eclim.el --- A company-mode completion back-end for eclim.
 
-;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -19,9 +19,14 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
-
 ;;; Commentary:
 ;;
+;; This completion backend is pretty barebone.
+;;
+;; `emacs-eclim' provides an alternative backend, and it also allows you to
+;; actually control Eclim from Emacs. Check it out.
+;;
+;; Eclim version 1.7.13 or newer (?) is required.
 
 ;;; Code:
 
@@ -61,28 +66,23 @@ eclim can only complete correctly when the buffer has been 
saved."
 (defvar company-eclim--doc nil)
 (make-variable-buffer-local 'company-eclim--doc)
 
-(defun company-eclim--buffer-lines ()
-  (goto-char (point-max))
-  (let (lines)
-    (while (= 0 (forward-line -1))
-      (push (buffer-substring-no-properties (point-at-bol) (point-at-eol))
-            lines))
-    lines))
-
 (defun company-eclim--call-process (&rest args)
   (let ((coding-system-for-read 'utf-8)
         res)
+    (require 'json)
     (with-temp-buffer
       (if (= 0 (setq res (apply 'call-process company-eclim-executable nil t 
nil
                                 "-command" args)))
-          (company-eclim--buffer-lines)
+          (let ((json-array-type 'list))
+            (goto-char (point-min))
+            (unless (eobp)
+              (json-read)))
         (message "Company-eclim command failed with error %d:\n%s" res
                  (buffer-substring (point-min) (point-max)))
         nil))))
 
 (defun company-eclim--project-list ()
-  (mapcar (lambda (line) (nreverse (split-string line " *- *" nil)))
-          (company-eclim--call-process "project_list")))
+  (company-eclim--call-process "project_list"))
 
 (defun company-eclim--project-dir ()
   (if (eq company-eclim--project-dir 'unknown)
@@ -95,8 +95,12 @@ eclim can only complete correctly when the buffer has been 
saved."
 (defun company-eclim--project-name ()
   (if (eq company-eclim--project-name 'unknown)
       (setq company-eclim--project-name
-            (car (cddr (assoc (company-eclim--project-dir)
-                              (company-eclim--project-list)))))
+            (let ((project (find-if (lambda (project)
+                                      (equal (cdr (assoc 'path project))
+                                             (company-eclim--project-dir)))
+                                    (company-eclim--project-list))))
+              (when project
+                (cdr (assoc 'name project)))))
     company-eclim--project-name))
 
 (defun company-eclim--candidates (prefix)
@@ -109,19 +113,28 @@ eclim can only complete correctly when the buffer has 
been saved."
         (basic-save-buffer))
       ;; FIXME: Sometimes this isn't finished when we complete.
       (company-eclim--call-process "java_src_update"
-                                  "-p" (company-eclim--project-name)
-                                  "-f" project-file))
+                                   "-p" (company-eclim--project-name)
+                                   "-f" project-file))
     (setq company-eclim--doc
-          (mapcar (lambda (line)
-                    (cdr (split-string line "|" nil)))
-                  (company-eclim--call-process
-                   "java_complete" "-p" (company-eclim--project-name)
-                   "-f" project-file
-                   "-o" (number-to-string (1- (point)))
-                   "-e" "utf-8"
-                   "-l" "standard"))))
+          (cdr (assoc 'completions
+                      (company-eclim--call-process
+                       "java_complete" "-p" (company-eclim--project-name)
+                       "-f" project-file
+                       "-o" (number-to-string (1- (point)))
+                       "-e" "utf-8"
+                       "-l" "standard")))))
   (let ((completion-ignore-case nil))
-    (all-completions prefix (mapcar 'car company-eclim--doc))))
+    ;; TODO: Handle overloaded methods somehow. Show one candidate per 
overload?
+    ;; That would look nice, but kinda useless: a bunch of candidates for the
+    ;; same completion. Maybe do expansion like 
`company-clang-objc-templatify'.
+    (all-completions prefix (mapcar (lambda (item) (cdr (assoc 'completion 
item)))
+                                    company-eclim--doc))))
+
+(defun company-eclim--meta (candidate)
+  (cdr (assoc 'info (find-if
+                     (lambda (item) (equal (cdr (assoc 'completion item))
+                                      arg))
+                     company-eclim--doc))))
 
 (defun company-eclim (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for eclim.
@@ -139,7 +152,8 @@ Completions only work correctly when the buffer has been 
saved.
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))
     (candidates (company-eclim--candidates arg))
-    (meta (cadr (assoc arg company-eclim--doc)))
+    (meta (company-eclim--meta arg))
+    (duplicates t)
     ;; because "" doesn't return everything
     (no-cache (equal arg ""))))
 
diff --git a/company.el b/company.el
index 174f129..081b3bf 100644
--- a/company.el
+++ b/company.el
@@ -344,7 +344,7 @@ Requires Emacs 24.1 or newer."
                           (plist-get (nthcdr 4 res) :predicate)))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-eclim company-semantic company-clang
+                              company-clang company-semantic company-eclim
                               company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
                                company-pysmell company-keywords)

commit 393453f1e22a10bbe7c56637500db8ff9223b30e
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 04:47:30 2013 +0400

    company--multi-backend-adapter: Skip backends that failed init

diff --git a/company.el b/company.el
index f728ca2..174f129 100644
--- a/company.el
+++ b/company.el
@@ -727,17 +727,19 @@ keymap during active completions (`company-active-map'):
     (apply 'company--multi-backend-adapter company-backend args)))
 
 (defun company--multi-backend-adapter (backends command &rest args)
-  (case command
-    (candidates
-     (apply 'append (mapcar (lambda (backend) (apply backend command args))
-                            backends)))
-    (sorted nil)
-    (duplicates t)
-    (otherwise
-     (let (value)
-       (dolist (backend backends)
-         (when (setq value (apply backend command args))
-           (return value)))))))
+  (let ((backends (remove-if (lambda (b) (eq 'failed (get b 'company-init)))
+                             backends)))
+    (case command
+      (candidates
+       (apply 'append (mapcar (lambda (backend) (apply backend command args))
+                              backends)))
+      (sorted nil)
+      (duplicates t)
+      (otherwise
+       (let (value)
+         (dolist (backend backends)
+           (when (setq value (apply backend command args))
+             (return value))))))))
 
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit d121d4ece2a4e973347db3404071419bf1c19e63
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 04:22:45 2013 +0400

    company-semantic: Don't load any Semantic packages ourselves

diff --git a/company-semantic.el b/company-semantic.el
index 1495059..c376710 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,6 +1,6 @@
 ;;; company-semantic.el --- A company-mode back-end using CEDET Semantic
 
-;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -26,10 +26,19 @@
 ;;; Code:
 
 (require 'company)
-(or (require 'semantic-analyze nil t)
-    (require 'semantic/analyze))
 (eval-when-compile (require 'cl))
 
+(defvar semantic-idle-summary-function)
+(declare-function semantic-documentation-for-tag "semantic/doc" )
+(declare-function semantic-analyze-current-context "semantic/analyze")
+(declare-function semantic-analyze-possible-completions "semantic/complete")
+(declare-function semantic-analyze-find-tags-by-prefix "semantic/analyze/fcn")
+(declare-function semantic-tag-class "semantic/tag")
+(declare-function semantic-tag-name "semantic/tag")
+(declare-function semantic-tag-start "semantic/tag")
+(declare-function semantic-tag-buffer "semantic/tag")
+(declare-function semantic-active-p "semantic")
+
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
   "The function turning a semantic tag into doc information."
   :group 'company
@@ -106,8 +115,9 @@ Symbols are chained by \".\" or \"->\"."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-semantic))
-    (prefix (and (memq major-mode company-semantic-modes)
+    (prefix (and (featurep 'semantic)
                  (semantic-active-p)
+                 (memq major-mode company-semantic-modes)
                  (not (company-in-string-or-comment))
                  (or (company-semantic--grab) 'stop)))
     (candidates (if (and (equal arg "")

commit f219f7fdcc19575c7890b7a7405bcdd1dd993881
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 03:44:41 2013 +0400

    company-clang: show meta

diff --git a/company-clang.el b/company-clang.el
index 160b9f8..966ef79 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -101,18 +101,24 @@ Prefix files (-include ...) can be selected with
 
 ;; TODO: How to handle OVERLOAD and Pattern?
 (defconst company-clang--completion-pattern
-  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)")
+  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)\\(?: : \\(.*\\)$\\)?")
 
 (defconst company-clang--error-buffer-name "*clang error*")
 
+(defvar company-clang--meta-cache nil)
+
 (defun company-clang--parse-output (prefix)
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
                          (regexp-quote prefix)))
         (case-fold-search nil)
         lines match)
+    (setq company-clang--meta-cache (make-hash-table :test 'equal))
     (while (re-search-forward pattern nil t)
       (setq match (match-string-no-properties 1))
+      (let ((meta (match-string-no-properties 2)))
+        (when (and meta (not (string= match meta)))
+          (puthash match meta company-clang--meta-cache)))
       (unless (equal match "Pattern")
         (push match lines)))
     lines))
@@ -225,6 +231,12 @@ Completions only work correctly when the buffer has been 
saved.
                  (not (company-in-string-or-comment))
                  (or (company-grab-symbol) 'stop)))
     (candidates (company-clang--candidates arg))
+    (meta (let ((meta (gethash arg company-clang--meta-cache)))
+            (when meta
+              (replace-regexp-in-string
+               "#]" " "
+               (replace-regexp-in-string "[<{[]#\\|#[>}]" "" meta t)
+               t))))
     (post-completion (and (derived-mode-p 'objc-mode)
                           (string-match ":" arg)
                           (company-clang-objc-templatify arg)))))
diff --git a/company.el b/company.el
index a841f98..f728ca2 100644
--- a/company.el
+++ b/company.el
@@ -77,6 +77,7 @@
 ;;    accidentally when it's enabled.
 ;;    Fixed two old tooltip annoyances.
 ;;    Some performance improvements.
+;;    `company-clang' now shows meta information, too.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)

commit 292684bd46ca5c9eb5a4ee6942b92f92896a716e
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 03:00:11 2013 +0400

    company-clang-guess-prefix: don't error out when no such file

diff --git a/company-clang.el b/company-clang.el
index 63486d0..160b9f8 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -1,6 +1,6 @@
 ;;; company-clang.el --- A company-mode completion back-end for clang
 
-;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
@@ -77,7 +77,7 @@ Prefix files (-include ...) can be selected with
   ;; Prefixes seem to be called .pch.  Pre-compiled headers do, too.
   ;; So we look at the magic number to rule them out.
   (let* ((file (company-clang--guess-pch-file buffer-file-name))
-         (magic-number (company-clang--file-substring file 0 4)))
+         (magic-number (and file (company-clang--file-substring file 0 4))))
     (unless (member magic-number '("CPCH" "gpch"))
       file)))
 

commit 25f2c535458972bb1309f7c602454bb56b656fd2
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 02:47:35 2013 +0400

    global-company-mode: don't turn on in invisible buffers
    
    Before: (js2-time (with-temp-buffer (fundamental-mode))) => 0.0282
    After:  (js2-time (with-temp-buffer (fundamental-mode))) => 0.0018

diff --git a/company.el b/company.el
index cebd6ca..a841f98 100644
--- a/company.el
+++ b/company.el
@@ -76,7 +76,7 @@
 ;;    used, so, for example, it's not as easy to circumvent `paredit-mode'
 ;;    accidentally when it's enabled.
 ;;    Fixed two old tooltip annoyances.
-;;    Improved tooltip performance.
+;;    Some performance improvements.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
@@ -622,7 +622,8 @@ keymap during active completions (`company-active-map'):
     (kill-local-variable 'company-point)))
 
 (define-globalized-minor-mode global-company-mode company-mode
-  (lambda () (company-mode 1)))
+  (lambda () (unless (or noninteractive (eq (aref (buffer-name) 0) ?\s))
+          (company-mode 1))))
 
 (defsubst company-assert-enabled ()
   (unless company-mode

commit 1043ae9a1eafc6f5cb3ffb60d1410a16afb8e2ff
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 02:30:24 2013 +0400

    No more duplicate elements in company--disabled-backends

diff --git a/company.el b/company.el
index 4edf651..cebd6ca 100644
--- a/company.el
+++ b/company.el
@@ -576,7 +576,7 @@ The work-around consists of adding a newline.")
          (unless (memq backend company--disabled-backends)
            (message "Company back-end '%s' could not be initialized:\n%s"
                     backend (error-message-string err)))
-         (push backend company--disabled-backends)
+         (pushnew backend company--disabled-backends)
          nil))
     (mapc 'company-init-backend backend)))
 

commit ac36be9b2ca1348cbd912ad2938d2c4fcc88b64c
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 17 22:53:31 2013 +0100

    * eldoc-eval.el: Inline old eldoc code only in 24.4.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index 88c5852..cede787 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -60,48 +60,47 @@ Should take one arg: the string to display"
 ;; with Emacs-24.4 show the eldoc info of current-buffer while
 ;; minibuffer is in use, disable this and inline old Emacs behavior.
 
-(and (boundp 'eldoc-message-function) (setq eldoc-message-function nil))
-
-;;; Inline old definition (24.3)
-;;
-(defun eldoc-message (&rest args)
-  (let ((omessage eldoc-last-message))
-    (setq eldoc-last-message
-         (cond ((eq (car args) eldoc-last-message) eldoc-last-message)
-               ((null (car args)) nil)
-               ;; If only one arg, no formatting to do, so put it in
-               ;; eldoc-last-message so eq test above might succeed on
-               ;; subsequent calls.
-               ((null (cdr args)) (car args))
-               (t (apply 'format args))))
-    ;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages
-    ;; are recorded in a log.  Do not put eldoc messages in that log since
-    ;; they are Legion.
-    ;; Emacs way of preventing log messages.
-    (let ((message-log-max nil))
-      (cond (eldoc-last-message (message "%s" eldoc-last-message))
-           (omessage (message nil)))))
-  eldoc-last-message)
-
-(defun eldoc-display-message-p ()
-  (and (eldoc-display-message-no-interference-p)
-       ;; If this-command is non-nil while running via an idle
-       ;; timer, we're still in the middle of executing a command,
-       ;; e.g. a query-replace where it would be annoying to
-       ;; overwrite the echo area.
-       (and (not this-command)
-           (symbolp last-command)
-           (intern-soft (symbol-name last-command)
-                        eldoc-message-commands))))
-
-(defun eldoc-display-message-no-interference-p ()
-  (and eldoc-mode
-       (not executing-kbd-macro)
-       (not (and (boundp 'edebug-active) edebug-active))
-       ;; Having this mode operate in an active minibuffer/echo area causes
-       ;; interference with what's going on there.
-       (not cursor-in-echo-area)
-       (not (eq (selected-window) (minibuffer-window)))))
+(when (boundp 'eldoc-message-function)
+  (setq eldoc-message-function nil)
+
+  (defun eldoc-message (&rest args)
+    (let ((omessage eldoc-last-message))
+      (setq eldoc-last-message
+            (cond ((eq (car args) eldoc-last-message) eldoc-last-message)
+                  ((null (car args)) nil)
+                  ;; If only one arg, no formatting to do, so put it in
+                  ;; eldoc-last-message so eq test above might succeed on
+                  ;; subsequent calls.
+                  ((null (cdr args)) (car args))
+                  (t (apply 'format args))))
+      ;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages
+      ;; are recorded in a log.  Do not put eldoc messages in that log since
+      ;; they are Legion.
+      ;; Emacs way of preventing log messages.
+      (let ((message-log-max nil))
+        (cond (eldoc-last-message (message "%s" eldoc-last-message))
+              (omessage (message nil)))))
+    eldoc-last-message)
+
+  (defun eldoc-display-message-p ()
+    (and (eldoc-display-message-no-interference-p)
+         ;; If this-command is non-nil while running via an idle
+         ;; timer, we're still in the middle of executing a command,
+         ;; e.g. a query-replace where it would be annoying to
+         ;; overwrite the echo area.
+         (and (not this-command)
+              (symbolp last-command)
+              (intern-soft (symbol-name last-command)
+                           eldoc-message-commands))))
+
+  (defun eldoc-display-message-no-interference-p ()
+    (and eldoc-mode
+         (not executing-kbd-macro)
+         (not (and (boundp 'edebug-active) edebug-active))
+         ;; Having this mode operate in an active minibuffer/echo area causes
+         ;; interference with what's going on there.
+         (not cursor-in-echo-area)
+         (not (eq (selected-window) (minibuffer-window))))))
 
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil

commit ba3e433b5b0c78ffe08637a167bda549d1077527
Author: Dmitry Gutov <address@hidden>
Date:   Mon Mar 18 00:51:01 2013 +0400

    Fix #2

diff --git a/company-clang.el b/company-clang.el
index 7613e31..63486d0 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -180,10 +180,9 @@ Prefix files (-include ...) can be selected with
 (defsubst company-clang-version ()
   "Return the version of `company-clang-executable'."
   (with-temp-buffer
-    (switch-to-buffer (current-buffer))
     (call-process company-clang-executable nil t nil "--version")
     (goto-char (point-min))
-    (if (re-search-forward "\\clang version \\([0-9.]+\\)" nil t)
+    (if (re-search-forward "clang version \\([0-9.]+\\)" nil t)
         (match-string-no-properties 1)
       "0")))
 

commit 5f961af80f5ca612dd74adace3fdcd3644a8078a
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 17 19:01:49 2013 +0100

    Fix compatibility with emacs-24.4.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index b806358..88c5852 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -22,8 +22,8 @@
 ;;; Commentary:
 
 ;;; Code:
-(require 'eldoc)
 
+(require 'eldoc)
 
 ;;; Minibuffer support.
 ;;  Enable displaying eldoc info in something else
@@ -55,6 +55,54 @@ Should take one arg: the string to display"
   :group 'lisp
   :type 'boolean)
 
+;;; Compatibility with Emacs-24.4
+;; New implementation of eldoc in minibuffer that come
+;; with Emacs-24.4 show the eldoc info of current-buffer while
+;; minibuffer is in use, disable this and inline old Emacs behavior.
+
+(and (boundp 'eldoc-message-function) (setq eldoc-message-function nil))
+
+;;; Inline old definition (24.3)
+;;
+(defun eldoc-message (&rest args)
+  (let ((omessage eldoc-last-message))
+    (setq eldoc-last-message
+         (cond ((eq (car args) eldoc-last-message) eldoc-last-message)
+               ((null (car args)) nil)
+               ;; If only one arg, no formatting to do, so put it in
+               ;; eldoc-last-message so eq test above might succeed on
+               ;; subsequent calls.
+               ((null (cdr args)) (car args))
+               (t (apply 'format args))))
+    ;; In emacs 19.29 and later, and XEmacs 19.13 and later, all messages
+    ;; are recorded in a log.  Do not put eldoc messages in that log since
+    ;; they are Legion.
+    ;; Emacs way of preventing log messages.
+    (let ((message-log-max nil))
+      (cond (eldoc-last-message (message "%s" eldoc-last-message))
+           (omessage (message nil)))))
+  eldoc-last-message)
+
+(defun eldoc-display-message-p ()
+  (and (eldoc-display-message-no-interference-p)
+       ;; If this-command is non-nil while running via an idle
+       ;; timer, we're still in the middle of executing a command,
+       ;; e.g. a query-replace where it would be annoying to
+       ;; overwrite the echo area.
+       (and (not this-command)
+           (symbolp last-command)
+           (intern-soft (symbol-name last-command)
+                        eldoc-message-commands))))
+
+(defun eldoc-display-message-no-interference-p ()
+  (and eldoc-mode
+       (not executing-kbd-macro)
+       (not (and (boundp 'edebug-active) edebug-active))
+       ;; Having this mode operate in an active minibuffer/echo area causes
+       ;; interference with what's going on there.
+       (not cursor-in-echo-area)
+       (not (eq (selected-window) (minibuffer-window)))))
+
 ;; Internal.
 (defvar eldoc-active-minibuffers-list nil
   "Store actives minibuffers with eldoc enabled.")

commit 9e572a0823cd101c9424652c7bccd510d60e5743
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 16 23:12:42 2013 +0400

    More succinct link sentence

diff --git a/README.md b/README.md
index 3cda743..db5f6b6 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-See <http://company-mode.github.com/> for more information.
+See the [homepage](http://company-mode.github.com/).

commit cb71facbe560a5155350dcc0466d4d47b8fa05dc
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 16 08:24:34 2013 +0400

    company-buffer-lines: Use vertical-motion
    
    So that we don't skip continuation lines

diff --git a/company.el b/company.el
index 8cdfa40..4edf651 100644
--- a/company.el
+++ b/company.el
@@ -1657,7 +1657,7 @@ Example:
 (defun company-buffer-lines (beg end)
   (goto-char beg)
   (let (lines)
-    (while (and (zerop (forward-line 1))
+    (while (and (= 1 (vertical-motion 1))
                 (<= (point) end))
       (push (buffer-substring beg (min end (1- (point)))) lines)
       (setq beg (point)))

commit b330d2ea8468fa102950f781205ec98c7942f44a
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 16 07:54:44 2013 +0400

    company-calculate-candidates: recognize already completed in different case
    
    Ignore case when appropriate while comparing the current prefix with the 
sole
    candidate.

diff --git a/company.el b/company.el
index cd82f0b..8cdfa40 100644
--- a/company.el
+++ b/company.el
@@ -866,11 +866,12 @@ can retrieve meta-data for them."
     (setq company-candidates nil)))
 
 (defun company-calculate-candidates (prefix)
-  (let ((candidates (cdr (assoc prefix company-candidates-cache))))
+  (let ((candidates (cdr (assoc prefix company-candidates-cache)))
+        (ignore-case (company-call-backend 'ignore-case)))
     (or candidates
         (when company-candidates-cache
           (let ((len (length prefix))
-                (completion-ignore-case (company-call-backend 'ignore-case))
+                (completion-ignore-case ignore-case)
                 prev)
             (dotimes (i (1+ len))
               (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
@@ -892,8 +893,10 @@ can retrieve meta-data for them."
               (while c2
                 (setcdr c2 (progn (while (equal (pop c2) (car c2)))
                                   c2)))))))
-    (if (or (cdr candidates)
-            (not (equal (car candidates) prefix)))
+    (if (and candidates
+             (or (cdr candidates)
+                 (not (eq t (compare-strings (car candidates) nil nil
+                                             prefix nil nil ignore-case)))))
         ;; Don't start when already completed and unique.
         candidates
       ;; Not the right place? maybe when setting?

commit 4cc87816c157ea2831a286a2264a1f259c535cc2
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 16 05:03:10 2013 +0400

    Add more words

diff --git a/README.md b/README.md
index 3e3a101..3cda743 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-See <http://company-mode.github.com/>.
+See <http://company-mode.github.com/> for more information.

commit 34875c88d73c92ca009c9d50e1d85aa9eabf7f32
Author: Dmitry Gutov <address@hidden>
Date:   Sat Mar 16 04:35:35 2013 +0400

    Move the whole description to the homepage

diff --git a/README.md b/README.md
index 8dce327..3e3a101 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1 @@
-Company Mode
-====
-
-About
-----
-
-Company is an Emacs extension for performing text completion.
-
-Completion candidates are retrieved from a variety of back-ends, such as
-`abbrev`, `Semantic`, `Eclim`, `etags`, etc.
-
-Screenshots
-----
-
-[<img src="screenshots/company-elisp.png" alt="company-elisp" 
width="256"/>](screenshots/company-elisp.png)
-[<img src="screenshots/company-cpp.png" alt="company-cpp" 
width="256"/>](screenshots/company-cpp.png)
-
-Installation
-----
-
-This package is part of [GNU ELPA](http://elpa.gnu.org/) (<kbd>M-x
-list-packages</kbd>).
-
-Usage
-----
-
-Once installed, enable `company-mode` with <kbd>M-x company-mode</kbd>.
-
-Completion will start automatically after you type a few letters. Use
-<kbd>M-n</kbd>, <kbd>M-p</kbd>, <kbd>\<tab\></kbd> and <kbd>\<return\></kbd> to
-complete. Search through the completions with <kbd>C-s</kbd>, <kbd>C-r</kbd> 
and
-<kbd>C-o</kbd>.
-
-To use `company-mode` in all buffers, add the following to your init file:
-
-    (global-company-mode)
-
-To set up preferred back-ends, customize `company-backends`.
-
-Also see this variable's docstring for information on writing a back-end.
-
-For more information, see the docstring for `company-mode`.
-
-Feedback
-----
-
-If you experience any problems or have a feature request, please use the
-[issue tracker](https://github.com/dgutov/company/issues).
+See <http://company-mode.github.com/>.
diff --git a/screenshots/company-cpp.png b/screenshots/company-cpp.png
deleted file mode 100644
index c2817ba..0000000
Binary files a/screenshots/company-cpp.png and /dev/null differ
diff --git a/screenshots/company-elisp.png b/screenshots/company-elisp.png
deleted file mode 100644
index c87c994..0000000
Binary files a/screenshots/company-elisp.png and /dev/null differ

commit fc4844b21da115448ddabce87735e0f6f69b102b
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 15 19:34:56 2013 +0400

    company-buffer-lines: Speed up
    
    I wonder what had been fixed in 9b2b5b6c623579057e9322bd44a7342d0b08ee92
    exactly. It will probably bite us later.

diff --git a/company.el b/company.el
index 8344b63..cd82f0b 100644
--- a/company.el
+++ b/company.el
@@ -76,6 +76,7 @@
 ;;    used, so, for example, it's not as easy to circumvent `paredit-mode'
 ;;    accidentally when it's enabled.
 ;;    Fixed two old tooltip annoyances.
+;;    Improved tooltip performance.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
@@ -1652,9 +1653,8 @@ Example:
 
 (defun company-buffer-lines (beg end)
   (goto-char beg)
-  (let ((row (company--row))
-        lines)
-    (while (and (equal (move-to-window-line (incf row)) row)
+  (let (lines)
+    (while (and (zerop (forward-line 1))
                 (<= (point) end))
       (push (buffer-substring beg (min end (1- (point)))) lines)
       (setq beg (point)))

commit afc950fec4b6b9d7c8e6ea48caa22cb36287c869
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 15 18:54:00 2013 +0400

    company-safe-substring: use a temp buffer
    
    * No more situations where we replace actual text with whitespace.
    
    * Still don't handle wide characters, except by untabifying in advance.
    
    * It's fast enough, although it woudln't hurt to replace most of the string
      splitting and munching in the callers with direct buffer manipulation.

diff --git a/company.el b/company.el
index fce59f7..8344b63 100644
--- a/company.el
+++ b/company.el
@@ -1437,15 +1437,18 @@ To show the number next to the candidates in some 
back-ends, enable
 (defsubst company-safe-substring (str from &optional to)
   (if (> from (string-width str))
       ""
-    (if to
-        (let* ((res (substring str from (min to (length str))))
-               (padding (- to from (string-width res)))
-               (cutting-comp (and (> (length str) to)
-                                  (get-text-property to 'composition str))))
-          (concat res
-                  (when (and (> padding 0) (not cutting-comp))
-                    (company-space-string padding))))
-      (substring str from))))
+    (with-temp-buffer
+      (insert str)
+      (move-to-column from)
+      (let ((beg (point)))
+        (if to
+            (progn
+              (move-to-column to)
+              (concat (buffer-substring beg (point))
+                      (let ((padding (- to (current-column))))
+                        (when (> padding 0)
+                          (company-space-string padding)))))
+          (buffer-substring beg (point-max)))))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit f08f6f6d960dec80eb8bf9749856e7364cc1bbf1
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 15 07:45:27 2013 +0400

    * company-safe-substring: consider composition when to <= str's width
    
    Still not perfect, but AFAICT writing a fully accurate `substring-by-width`
    function would be wasteful performance-wise.

diff --git a/company.el b/company.el
index 51525cb..fce59f7 100644
--- a/company.el
+++ b/company.el
@@ -1435,13 +1435,17 @@ To show the number next to the candidates in some 
back-ends, enable
     (make-string len ?\ )))
 
 (defsubst company-safe-substring (str from &optional to)
-  (let ((len (string-width str)))
-    (if (> from len)
-        ""
-      (if (and to (> to len))
-          (concat (substring str from)
-                  (company-space-string (- to len)))
-        (substring str from to)))))
+  (if (> from (string-width str))
+      ""
+    (if to
+        (let* ((res (substring str from (min to (length str))))
+               (padding (- to from (string-width res)))
+               (cutting-comp (and (> (length str) to)
+                                  (get-text-property to 'composition str))))
+          (concat res
+                  (when (and (> padding 0) (not cutting-comp))
+                    (company-space-string padding))))
+      (substring str from))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit d861f1d075faf63ef11af087b0d53c19b08867da
Author: Dmitry Gutov <address@hidden>
Date:   Fri Mar 15 06:01:03 2013 +0400

    Fix two tooltip problems
    
    * company-safe-substring: take into account character composition.
    * company--replacement-string: append default face everywhere, so that we 
never
      inherit face background from the character at the end of the overlay.

diff --git a/company.el b/company.el
index 364440b..51525cb 100644
--- a/company.el
+++ b/company.el
@@ -75,6 +75,7 @@
 ;;    the completion keymap is active, other minor modes' keymaps are still
 ;;    used, so, for example, it's not as easy to circumvent `paredit-mode'
 ;;    accidentally when it's enabled.
+;;    Fixed two old tooltip annoyances.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
@@ -1434,7 +1435,7 @@ To show the number next to the candidates in some 
back-ends, enable
     (make-string len ?\ )))
 
 (defsubst company-safe-substring (str from &optional to)
-  (let ((len (length str)))
+  (let ((len (string-width str)))
     (if (> from len)
         ""
       (if (and to (> to len))
@@ -1681,9 +1682,12 @@ Example:
     ;; Append whole new lines.
     (while lines
       (push (concat (company-space-string column) (pop lines)) new))
-    (concat (when nl "\n")
-            (mapconcat 'identity (nreverse new) "\n")
-            "\n")))
+
+    (let ((str (concat (when nl "\n")
+                       (mapconcat 'identity (nreverse new) "\n")
+                       "\n")))
+      (font-lock-append-text-property 0 (length str) 'face 'default str)
+      str)))
 
 (defun company--create-lines (selection limit)
 

commit 9108df1d0052c70998dee701c58abfb74e36c0ed
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 03:36:28 2013 +0400

    Tweak README#Feedback

diff --git a/README.md b/README.md
index cd8619e..8dce327 100644
--- a/README.md
+++ b/README.md
@@ -44,5 +44,5 @@ For more information, see the docstring for `company-mode`.
 Feedback
 ----
 
-If you experience any problems or have a feature request, use the
-[Issue Tracker](https://github.com/dgutov/company/issues).
+If you experience any problems or have a feature request, please use the
+[issue tracker](https://github.com/dgutov/company/issues).

commit 7331c6efd2c9569da8aeecda8d64a421a157b5dc
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 03:24:12 2013 +0400

    Make company-capf work

diff --git a/company.el b/company.el
index f5e0f01..364440b 100644
--- a/company.el
+++ b/company.el
@@ -319,7 +319,8 @@ If this many lines are not available, prefer to display the 
tooltip above."
                 (return t))))))
 
 (defun company-capf (command &optional arg &rest args)
-  "Adapter for Company completion to use `completion-at-point-functions'."
+  "`company-mode' back-end using `completion-at-point-functions'.
+Requires Emacs 24.1 or newer."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-capf))
@@ -328,19 +329,18 @@ If this many lines are not available, prefer to display 
the tooltip above."
                                   ;; Ignore misbehaving functions.
                                   #'completion--capf-wrapper 'optimist)))
        (when (consp res)
-         (if (> (nth 1 res) (point))
+         (if (> (nth 2 res) (point))
              'stop
-           (buffer-substring-no-properties (nth 0 res) (point))))))
+           (buffer-substring-no-properties (nth 1 res) (point))))))
     (candidates
      (let ((res (run-hook-wrapped 'completion-at-point-functions
                                   ;; Ignore misbehaving functions.
                                   #'completion--capf-wrapper 'optimist)))
        (when (consp res)
-         (all-completions arg (nth 2 res)
-                          (plist-get (nthcdr 3 res) :predicate)))))))
+         (all-completions arg (nth 3 res)
+                          (plist-get (nthcdr 4 res) :predicate)))))))
 
-(defcustom company-backends '(;; company-capf ;FIXME: Untested!
-                              company-elisp company-nxml company-css
+(defcustom company-backends '(company-elisp company-nxml company-css
                               company-eclim company-semantic company-clang
                               company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code

commit 739760229c25979f00456ce62b0bf729d6e6fcda
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 02:47:15 2013 +0400

    * company--should-complete: not in minibuffer

diff --git a/company.el b/company.el
index 0e80997..f5e0f01 100644
--- a/company.el
+++ b/company.el
@@ -1,6 +1,6 @@
 ;;; company.el --- Extensible inline text completion mechanism
 
-;; Copyright (C) 2009-2012  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2013  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 ;; Version: 0.5
@@ -807,7 +807,8 @@ can retrieve meta-data for them."
 
 (defun company--should-complete ()
   (and (not (or buffer-read-only overriding-terminal-local-map
-                overriding-local-map))
+                overriding-local-map
+                (minibufferp)))
        ;; Check if in the middle of entering a key combination.
        (or (equal (this-command-keys-vector) [])
            (not (keymapp (key-binding (this-command-keys-vector)))))

commit 8bf39d5e3ee15eb9c4fd111eb08e081e2cfdb513
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:29:10 2013 +0400

    Backquote "company-mode"

diff --git a/README.md b/README.md
index 6aa95dc..cd8619e 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ list-packages</kbd>).
 Usage
 ----
 
-Once installed, enable company-mode with <kbd>M-x company-mode</kbd>.
+Once installed, enable `company-mode` with <kbd>M-x company-mode</kbd>.
 
 Completion will start automatically after you type a few letters. Use
 <kbd>M-n</kbd>, <kbd>M-p</kbd>, <kbd>\<tab\></kbd> and <kbd>\<return\></kbd> to

commit 0b6d832a8d1a7db39b1d6fbd877bb5139ded6c06
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:27:53 2013 +0400

    Fix typo, remove "modular"

diff --git a/README.md b/README.md
index 894de1c..6aa95dc 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,9 @@ About
 ----
 
 Company is an Emacs extension for performing text completion.
-Completion candidates are retrieved from a variety of modular
-back-ends, such as `abbrev`, `Semantic`, `Eclim`, `etags`, etc.
+
+Completion candidates are retrieved from a variety of back-ends, such as
+`abbrev`, `Semantic`, `Eclim`, `etags`, etc.
 
 Screenshots
 ----
@@ -30,7 +31,7 @@ Completion will start automatically after you type a few 
letters. Use
 complete. Search through the completions with <kbd>C-s</kbd>, <kbd>C-r</kbd> 
and
 <kbd>C-o</kbd>.
 
-To use `company-mode` is all buffers, add the following to your init file:
+To use `company-mode` in all buffers, add the following to your init file:
 
     (global-company-mode)
 

commit 9e1a4d8a3b4b738e238ac6a385ab9f1434f805f8
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:19:51 2013 +0400

    Escape the angle brackets

diff --git a/README.md b/README.md
index f636e58..894de1c 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ Usage
 Once installed, enable company-mode with <kbd>M-x company-mode</kbd>.
 
 Completion will start automatically after you type a few letters. Use
-<kbd>M-n</kbd>, <kbd>M-p</kbd>, <kbd><tab></kbd> and <kbd><return></kbd> to
+<kbd>M-n</kbd>, <kbd>M-p</kbd>, <kbd>\<tab\></kbd> and <kbd>\<return\></kbd> to
 complete. Search through the completions with <kbd>C-s</kbd>, <kbd>C-r</kbd> 
and
 <kbd>C-o</kbd>.
 

commit 9b1f9009d934ec917bf4770518df9dd5b4fe2f1a
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:16:25 2013 +0400

    And another one

diff --git a/README.md b/README.md
index ecf56fd..f636e58 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ back-ends, such as `abbrev`, `Semantic`, `Eclim`, `etags`, 
etc.
 Screenshots
 ----
 
-[<img src="screenshots/company-elisp.png" alt="company-elisp" 
width="256/>](screenshots/company-elisp.png)
+[<img src="screenshots/company-elisp.png" alt="company-elisp" 
width="256"/>](screenshots/company-elisp.png)
 [<img src="screenshots/company-cpp.png" alt="company-cpp" 
width="256"/>](screenshots/company-cpp.png)
 
 Installation

commit d3dda607ca2c34ddfed658ab52833ec8741d7c10
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:15:25 2013 +0400

    Add missing quote

diff --git a/README.md b/README.md
index af9d28b..ecf56fd 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Screenshots
 ----
 
 [<img src="screenshots/company-elisp.png" alt="company-elisp" 
width="256/>](screenshots/company-elisp.png)
-[<img src="screenshots/company-cpp.png" alt="company-cpp" 
width="256/>](screenshots/company-cpp.png)
+[<img src="screenshots/company-cpp.png" alt="company-cpp" 
width="256"/>](screenshots/company-cpp.png)
 
 Installation
 ----

commit a97240339cf2fc42c0df5d66e0602e8c49e6e9d7
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 14 01:13:55 2013 +0400

    Improve the README, add old screenshots

diff --git a/README.md b/README.md
index ff48917..af9d28b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,47 @@
-Company is an Emacs extension for performing text completion.
-Completion candidates are retrieved from a variety of modular
-back-ends, such as Semantic.
-
-Once installed, enable company-mode with <kbd>M-x company-mode</kbd>.
-For further information, see the docstring for `company-mode`.
+Company Mode
+====
+
+About
+----
+
+Company is an Emacs extension for performing text completion.
+Completion candidates are retrieved from a variety of modular
+back-ends, such as `abbrev`, `Semantic`, `Eclim`, `etags`, etc.
+
+Screenshots
+----
+
+[<img src="screenshots/company-elisp.png" alt="company-elisp" 
width="256/>](screenshots/company-elisp.png)
+[<img src="screenshots/company-cpp.png" alt="company-cpp" 
width="256/>](screenshots/company-cpp.png)
+
+Installation
+----
+
+This package is part of [GNU ELPA](http://elpa.gnu.org/) (<kbd>M-x
+list-packages</kbd>).
+
+Usage
+----
+
+Once installed, enable company-mode with <kbd>M-x company-mode</kbd>.
+
+Completion will start automatically after you type a few letters. Use
+<kbd>M-n</kbd>, <kbd>M-p</kbd>, <kbd><tab></kbd> and <kbd><return></kbd> to
+complete. Search through the completions with <kbd>C-s</kbd>, <kbd>C-r</kbd> 
and
+<kbd>C-o</kbd>.
+
+To use `company-mode` is all buffers, add the following to your init file:
+
+    (global-company-mode)
+
+To set up preferred back-ends, customize `company-backends`.
+
+Also see this variable's docstring for information on writing a back-end.
+
+For more information, see the docstring for `company-mode`.
+
+Feedback
+----
+
+If you experience any problems or have a feature request, use the
+[Issue Tracker](https://github.com/dgutov/company/issues).
diff --git a/screenshots/company-cpp.png b/screenshots/company-cpp.png
new file mode 100644
index 0000000..c2817ba
Binary files /dev/null and b/screenshots/company-cpp.png differ
diff --git a/screenshots/company-elisp.png b/screenshots/company-elisp.png
new file mode 100644
index 0000000..c87c994
Binary files /dev/null and b/screenshots/company-elisp.png differ

commit 6d9d3032e24eeb856115b6309b2ffbbbb8dbcf38
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 13 23:44:41 2013 +0400

    Update copyright dates and the changelog

diff --git a/company-elisp.el b/company-elisp.el
index c45e873..ec3161d 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,6 +1,6 @@
 ;;; company-elisp.el --- A company-mode completion back-end for emacs-lisp-mode
 
-;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011-2012  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 
diff --git a/company.el b/company.el
index b3606ed..0e80997 100644
--- a/company.el
+++ b/company.el
@@ -1,6 +1,6 @@
 ;;; company.el --- Extensible inline text completion mechanism
 
-;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+;; Copyright (C) 2009-2012  Free Software Foundation, Inc.
 
 ;; Author: Nikolaj Schumacher
 ;; Version: 0.5
@@ -65,9 +65,16 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Switching tags now works correctly in `company-etags'.
+;;    Clang completions now include macros and are case-sensitive.
 ;;    Added `company-capf': completion adapter using
 ;;    `completion-at-point-functions'.  (Stefan Monnier)
-;;    Switching tags now works correctly in `company-etags'.
+;;    `company-elisp' has some improvements.
+;;    Instead of `overrriding-terminal-local-map', we're now using
+;;    `emulation-mode-map-alists' (experimental).  This largely means that when
+;;    the completion keymap is active, other minor modes' keymaps are still
+;;    used, so, for example, it's not as easy to circumvent `paredit-mode'
+;;    accidentally when it's enabled.
 ;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)

commit 8b7d5ff1768dc573b9d2e64d1fc8a5973de163b9
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 13 06:14:14 2013 +0400

    Remove leading asterisks from docstrings
    
    They don't make variables customizable anymore.

diff --git a/company-clang.el b/company-clang.el
index 7cb85e3..7613e31 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -30,19 +30,19 @@
 
 (defcustom company-clang-executable
   (executable-find "clang")
-  "*Location of clang executable."
+  "Location of clang executable."
   :group 'company-clang
   :type 'file)
 
 (defcustom company-clang-auto-save t
-  "*Determines whether to save the buffer when retrieving completions.
+  "Determines whether to save the buffer when retrieving completions.
 clang can only complete correctly when the buffer has been saved."
   :group 'company-clang
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
 (defcustom company-clang-arguments nil
-  "*Additional arguments to pass to clang when completing.
+  "Additional arguments to pass to clang when completing.
 Prefix files (-include ...) can be selected with
 `company-clang-set-prefix' or automatically through a custom
 `company-clang-prefix-guesser'."
@@ -50,7 +50,7 @@ Prefix files (-include ...) can be selected with
   :type '(repeat (string :tag "Argument" nil)))
 
 (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
-  "*A function to determine the prefix file for the current buffer."
+  "A function to determine the prefix file for the current buffer."
   :group 'company-clang
   :type '(function :tag "Guesser function" nil))
 
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 5cedcc4..64f60c7 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -35,7 +35,7 @@
     haskell-mode java-mode javascript-mode jde-mode js2-mode lisp-mode
     lua-mode objc-mode perl-mode php-mode python-mode ruby-mode scheme-mode
     shell-script-mode)
-  "*Modes that use `company-dabbrev-code'.
+  "Modes that use `company-dabbrev-code'.
 In all these modes `company-dabbrev-code' will complete only symbols, not text
 in comments or strings.  In other modes `company-dabbrev-code' will pass 
control
 to other back-ends \(e.g. `company-dabbrev'\).
@@ -45,7 +45,7 @@ Value t means complete in all modes."
                  (const tag "All modes" t)))
 
 (defcustom company-dabbrev-code-other-buffers t
-  "*Determines whether `company-dabbrev-code' should search other buffers.
+  "Determines whether `company-dabbrev-code' should search other buffers.
 If `all', search all other buffers.  If t, search buffers with the same
 major mode.
 See also `company-dabbrev-code-time-limit'."
@@ -55,7 +55,7 @@ See also `company-dabbrev-code-time-limit'."
                  (const :tag "All" all)))
 
 (defcustom company-dabbrev-code-time-limit .5
-  "*Determines how long `company-dabbrev-code' should look for matches."
+  "Determines how long `company-dabbrev-code' should look for matches."
   :group 'company
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 03223cf..5f43b83 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -29,7 +29,7 @@
 (eval-when-compile (require 'cl))
 
 (defcustom company-dabbrev-other-buffers 'all
-  "*Determines whether `company-dabbrev' should search other buffers.
+  "Determines whether `company-dabbrev' should search other buffers.
 If `all', search all other buffers.  If t, search buffers with the same
 major mode.
 See also `company-dabbrev-time-limit'."
@@ -39,13 +39,13 @@ See also `company-dabbrev-time-limit'."
                  (const :tag "All" all)))
 
 (defcustom company-dabbrev-time-limit .5
-  "*Determines how many seconds `company-dabbrev' should look for matches."
+  "Determines how many seconds `company-dabbrev' should look for matches."
   :group 'company
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
 
 (defcustom company-dabbrev-char-regexp "\\sw"
-  "*A regular expression matching the characters `company-dabbrev' looks for."
+  "A regular expression matching the characters `company-dabbrev' looks for."
   :group 'company
   :type 'regexp)
 
diff --git a/company-eclim.el b/company-eclim.el
index be08fa0..db486c1 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -39,12 +39,12 @@
 
 (defcustom company-eclim-executable
   (or (executable-find "eclim") (company-eclim-executable-find))
-  "*Location of eclim executable."
+  "Location of eclim executable."
   :group 'company
   :type 'file)
 
 (defcustom company-eclim-auto-save t
-  "*Determines whether to save the buffer when retrieving completions.
+  "Determines whether to save the buffer when retrieving completions.
 eclim can only complete correctly when the buffer has been saved."
   :group 'company
   :type '(choice (const :tag "Off" nil)
diff --git a/company-elisp.el b/company-elisp.el
index f3a1809..c45e873 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -30,7 +30,7 @@
 (require 'help-mode)
 
 (defcustom company-elisp-detect-function-context t
-  "*If enabled, offer Lisp functions only in appropriate contexts.
+  "If enabled, offer Lisp functions only in appropriate contexts.
 Functions are offered for completion only after ' and \(."
   :group 'company
   :type '(choice (const :tag "Off" nil)
diff --git a/company-etags.el b/company-etags.el
index 6807f98..508aac8 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -29,7 +29,7 @@
 (require 'etags)
 
 (defcustom company-etags-use-main-table-list t
-  "*Always search `tags-table-list' if set.
+  "Always search `tags-table-list' if set.
 If this is disabled, `company-etags' will try to find the one table for each
 buffer automatically."
   :group 'company-mode
diff --git a/company-gtags.el b/company-gtags.el
index 62c9707..59ad7c8 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -30,7 +30,7 @@
 
 (defcustom company-gtags-executable
   (executable-find "global")
-  "*Location of GNU global executable."
+  "Location of GNU global executable."
   :type 'string
   :group 'company)
 
diff --git a/company-ispell.el b/company-ispell.el
index 05266af..8a73988 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -30,7 +30,7 @@
 (eval-when-compile (require 'cl))
 
 (defcustom company-ispell-dictionary nil
-  "*Dictionary to use for `company-ispell'.
+  "Dictionary to use for `company-ispell'.
 If nil, use `ispell-complete-word-dict'."
   :group 'company
   :type '(choice (const :tag "default (nil)" nil)
diff --git a/company-keywords.el b/company-keywords.el
index 88af112..20bd7b0 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -212,7 +212,7 @@
     (espresso-mode . javascript-mode)
     (cperl-mode . perl-mode)
     (jde-mode . java-mode))
-  "*Alist mapping major-modes to sorted keywords for `company-keywords'.")
+  "Alist mapping major-modes to sorted keywords for `company-keywords'.")
 
 ;;;###autoload
 (defun company-keywords (command &optional arg &rest ignored)
diff --git a/company-semantic.el b/company-semantic.el
index eacf1c7..1495059 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -31,7 +31,7 @@
 (eval-when-compile (require 'cl))
 
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
-  "*The function turning a semantic tag into doc information."
+  "The function turning a semantic tag into doc information."
   :group 'company
   :type 'function)
 
diff --git a/company-template.el b/company-template.el
index 53d9687..69eac7c 100644
--- a/company-template.el
+++ b/company-template.el
@@ -26,7 +26,7 @@
 (defface company-template-field
   '((((background dark)) (:background "yellow" :foreground "black"))
     (((background light)) (:background "orange" :foreground "black")))
-  "*Face used for editable text in template fields."
+  "Face used for editable text in template fields."
   :group 'company)
 
 (defvar company-template-nav-map
diff --git a/company-xcode.el b/company-xcode.el
index 42e00de..b558fe8 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -29,7 +29,7 @@
 (eval-when-compile (require 'cl))
 
 (defcustom company-xcode-xcodeindex-executable (executable-find "xcodeindex")
-  "*Location of xcodeindex executable."
+  "Location of xcodeindex executable."
   :group 'company-xcode
   :type 'file)
 
@@ -43,7 +43,7 @@
 (defcustom company-xcode-types
   '("Class" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
     "Type" "Union" "Function")
-  "*The types of symbols offered by `company-xcode'.
+  "The types of symbols offered by `company-xcode'.
 No context-enabled completion is available.  Types like methods will be
 offered regardless of whether the class supports them.  The defaults should be
 valid in most contexts."
diff --git a/company.el b/company.el
index 142ecab..b3606ed 100644
--- a/company.el
+++ b/company.el
@@ -158,59 +158,59 @@
 (defface company-tooltip
   '((t :background "yellow"
        :foreground "black"))
-  "*Face used for the tool tip."
+  "Face used for the tool tip."
   :group 'company)
 
 (defface company-tooltip-selection
   '((default :inherit company-tooltip)
     (((class color) (min-colors 88)) (:background "orange1"))
     (t (:background "green")))
-  "*Face used for the selection in the tool tip."
+  "Face used for the selection in the tool tip."
   :group 'company)
 
 (defface company-tooltip-mouse
   '((default :inherit highlight))
-  "*Face used for the tool tip item under the mouse."
+  "Face used for the tool tip item under the mouse."
   :group 'company)
 
 (defface company-tooltip-common
   '((t :inherit company-tooltip
        :foreground "red"))
-  "*Face used for the common completion in the tool tip."
+  "Face used for the common completion in the tool tip."
   :group 'company)
 
 (defface company-tooltip-common-selection
   '((t :inherit company-tooltip-selection
        :foreground "red"))
-  "*Face used for the selected common completion in the tool tip."
+  "Face used for the selected common completion in the tool tip."
   :group 'company)
 
 (defface company-preview
   '((t :background "blue4"
        :foreground "wheat"))
-  "*Face used for the completion preview."
+  "Face used for the completion preview."
   :group 'company)
 
 (defface company-preview-common
   '((t :inherit company-preview
        :foreground "red"))
-  "*Face used for the common part of the completion preview."
+  "Face used for the common part of the completion preview."
   :group 'company)
 
 (defface company-preview-search
   '((t :inherit company-preview
        :background "blue1"))
-  "*Face used for the search string in the completion preview."
+  "Face used for the search string in the completion preview."
   :group 'company)
 
 (defface company-echo nil
-  "*Face used for completions in the echo area."
+  "Face used for completions in the echo area."
   :group 'company)
 
 (defface company-echo-common
   '((((background dark)) (:foreground "firebrick1"))
     (((background light)) (:background "firebrick4")))
-  "*Face used for the common part of completions in the echo area."
+  "Face used for the common part of completions in the echo area."
   :group 'company)
 
 (defun company-frontends-set (variable value)
@@ -235,7 +235,7 @@
 (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
                                company-preview-if-just-one-frontend
                                company-echo-metadata-frontend)
-  "*The list of active front-ends (visualizations).
+  "The list of active front-ends (visualizations).
 Each front-end is a function that takes one argument.  It is called with
 one of the following arguments:
 
@@ -271,12 +271,12 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                          (function :tag "custom function" nil))))
 
 (defcustom company-tooltip-limit 10
-  "*The maximum number of candidates in the tool tip"
+  "The maximum number of candidates in the tool tip"
   :group 'company
   :type 'integer)
 
 (defcustom company-tooltip-minimum 6
-  "*The minimum height of the tool tip.
+  "The minimum height of the tool tip.
 If this many lines are not available, prefer to display the tooltip above."
   :group 'company
   :type 'integer)
@@ -339,7 +339,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
                               (company-gtags company-etags company-dabbrev-code
                                company-pysmell company-keywords)
                               company-oddmuse company-files company-dabbrev)
-  "*The list of active back-ends (completion engines).
+  "The list of active back-ends (completion engines).
 Each list elements can itself be a list of back-ends.  In that case their
 completions are merged.  Otherwise only the first matching back-end returns
 results.
@@ -410,32 +410,32 @@ does not know about.  It should also be callable 
interactively and use
 (put 'company-backends 'safe-local-variable 'company-safe-backends-p)
 
 (defcustom company-completion-started-hook nil
-  "*Hook run when company starts completing.
+  "Hook run when company starts completing.
 The hook is called with one argument that is non-nil if the completion was
 started manually."
   :group 'company
   :type 'hook)
 
 (defcustom company-completion-cancelled-hook nil
-  "*Hook run when company cancels completing.
+  "Hook run when company cancels completing.
 The hook is called with one argument that is non-nil if the completion was
 aborted manually."
   :group 'company
   :type 'hook)
 
 (defcustom company-completion-finished-hook nil
-  "*Hook run when company successfully completes.
+  "Hook run when company successfully completes.
 The hook is called with the selected candidate as an argument."
   :group 'company
   :type 'hook)
 
 (defcustom company-minimum-prefix-length 3
-  "*The minimum prefix length for automatic completion."
+  "The minimum prefix length for automatic completion."
   :group 'company
   :type '(integer :tag "prefix length"))
 
 (defcustom company-require-match 'company-explicit-action-p
-  "*If enabled, disallow non-matching input.
+  "If enabled, disallow non-matching input.
 This can be a function do determine if a match is required.
 
 This can be overridden by the back-end, if it returns t or 'never to
@@ -488,7 +488,7 @@ A character that is part of a valid candidate never starts 
auto-completion."
                  (function :tag "Predicate function")))
 
 (defcustom company-idle-delay .7
-  "*The idle delay in seconds until automatic completions starts.
+  "The idle delay in seconds until automatic completions starts.
 A value of nil means never complete automatically, t means complete
 immediately when a prefix of `company-minimum-prefix-length' is reached."
   :group 'company
@@ -497,7 +497,7 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
                  (number :tag "seconds")))
 
 (defcustom company-begin-commands t
-  "*A list of commands following which company will start completing.
+  "A list of commands following which company will start completing.
 If this is t, it will complete after any command.  See `company-idle-delay'.
 
 Alternatively any command with a non-nil 'company-begin property is treated as
@@ -508,13 +508,13 @@ if it was on this list."
                  (repeat :tag "Commands" function)))
 
 (defcustom company-show-numbers nil
-  "*If enabled, show quick-access numbers for the first ten candidates."
+  "If enabled, show quick-access numbers for the first ten candidates."
   :group 'company
   :type '(choice (const :tag "off" nil)
                  (const :tag "on" t)))
 
 (defvar company-end-of-buffer-workaround t
-  "*Work around a visualization bug when completing at the end of the buffer.
+  "Work around a visualization bug when completing at the end of the buffer.
 The work-around consists of adding a newline.")
 
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -578,7 +578,7 @@ The work-around consists of adding a newline.")
 
 ;;;###autoload
 (define-minor-mode company-mode
-  "\"complete anything\"; in in-buffer completion framework.
+  "\"complete anything\"; is an in-buffer completion framework.
 Completion starts automatically, depending on the values
 `company-idle-delay' and `company-minimum-prefix-length'.
 

commit cb0a58684509ba5d3546d7d08a11b136ca294c11
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 13 05:58:20 2013 +0400

    Merge changes from the GNU ELPA repository
    
    * Add company-capf: adapter for `completion-at-point-functions'.
    * Lots of header and docstring tweaks.
    * Copy README to README.md, adjust formatting.

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ff48917
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+Company is an Emacs extension for performing text completion.
+Completion candidates are retrieved from a variety of modular
+back-ends, such as Semantic.
+
+Once installed, enable company-mode with <kbd>M-x company-mode</kbd>.
+For further information, see the docstring for `company-mode`.
diff --git a/company-abbrev.el b/company-abbrev.el
index 57939e8..a28c88d 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -1,21 +1,29 @@
-;;; company-abbrev.el --- a company-mode completion back-end for abbrev
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-abbrev.el --- A company-mode completion back-end for abbrev
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
diff --git a/company-clang.el b/company-clang.el
index 73825f2..7cb85e3 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -1,28 +1,36 @@
-;;; company-clang.el --- a company-mode completion back-end for clang
-;;
-;; Copyright (C) 2010 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-clang.el --- A company-mode completion back-end for clang
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
 
 (defcustom company-clang-executable
   (executable-find "clang")
-  "*Location of clang executable"
+  "*Location of clang executable."
   :group 'company-clang
   :type 'file)
 
diff --git a/company-css.el b/company-css.el
index 6c8f4c0..6546a10 100644
--- a/company-css.el
+++ b/company-css.el
@@ -1,21 +1,27 @@
-;;; company-css.el --- a company-mode completion back-end for css-mode
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-css.el --- A company-mode completion back-end for css-mode
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
@@ -241,7 +247,7 @@
           "\\)*"
           "\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)"
           "\\=")
-  "A regular expression matching CSS tags")
+  "A regular expression matching CSS tags.")
 
 ;;; pseudo id
 (defconst company-css-pseudo-regexp
@@ -255,7 +261,7 @@
           "\\)*"
           "\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):"
           "\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=")
-  "A regular expression matching CSS pseudo classes")
+  "A regular expression matching CSS pseudo classes.")
 
 ;;; properties
 
@@ -268,7 +274,7 @@ Returns \"\" if no property found, but feasible at this 
position."
 ;;; values
 (defconst company-css-property-value-regexp
   "\\_<\\([[:alpha:]-]+\\):\\(?:[^};]*[[:space:]]+\\)?\\([^};]*\\_>\\|\\)\\="
-  "A regular expression matching CSS tags")
+  "A regular expression matching CSS tags.")
 
 ;;;###autoload
 (defun company-css (command &optional arg &rest ignored)
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 5d962e2..5cedcc4 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -1,21 +1,29 @@
-;;; company-dabbrev-code.el --- a dabbrev-like company-mode back-end for code
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-dabbrev-code.el --- A dabbrev-like company-mode back-end for code
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (require 'company-dabbrev)
@@ -38,8 +46,8 @@ Value t means complete in all modes."
 
 (defcustom company-dabbrev-code-other-buffers t
   "*Determines whether `company-dabbrev-code' should search other buffers.
-If 'all, search all other buffers.  If t, search buffers with the same
-major-mode.
+If `all', search all other buffers.  If t, search buffers with the same
+major mode.
 See also `company-dabbrev-code-time-limit'."
   :group 'company
   :type '(choice (const :tag "Off" nil)
diff --git a/company-dabbrev.el b/company-dabbrev.el
index f4453e9..03223cf 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -1,29 +1,37 @@
-;;; company-dabbrev.el --- a dabbrev-like company-mode completion back-end
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-dabbrev.el --- A dabbrev-like company-mode completion back-end
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
 
 (defcustom company-dabbrev-other-buffers 'all
   "*Determines whether `company-dabbrev' should search other buffers.
-If 'all, search all other buffers.  If t, search buffers with the same
-major-mode.
+If `all', search all other buffers.  If t, search buffers with the same
+major mode.
 See also `company-dabbrev-time-limit'."
   :group 'company
   :type '(choice (const :tag "Off" nil)
diff --git a/company-eclim.el b/company-eclim.el
index f28bdb0..be08fa0 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,21 +1,29 @@
-;;; company-eclim.el --- a company-mode completion back-end for eclim.
-;;
-;; Copyright (C) 2009-2010 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-eclim.el --- A company-mode completion back-end for eclim.
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
@@ -31,7 +39,7 @@
 
 (defcustom company-eclim-executable
   (or (executable-find "eclim") (company-eclim-executable-find))
-  "*Location of eclim executable"
+  "*Location of eclim executable."
   :group 'company
   :type 'file)
 
diff --git a/company-elisp.el b/company-elisp.el
index 1073f28..f3a1809 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,28 +1,36 @@
-;;; company-elisp.el --- a company-mode completion back-end for emacs-lisp-mode
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-elisp.el --- A company-mode completion back-end for emacs-lisp-mode
+
+;; Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
 (require 'help-mode)
 
 (defcustom company-elisp-detect-function-context t
-  "*If enabled, offer lisp functions only in appropriate contexts.
+  "*If enabled, offer Lisp functions only in appropriate contexts.
 Functions are offered for completion only after ' and \(."
   :group 'company
   :type '(choice (const :tag "Off" nil)
diff --git a/company-etags.el b/company-etags.el
index a4c2f1d..6807f98 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -1,21 +1,29 @@
-;;; company-etags.el --- a company-mode completion back-end for etags
-;;
-;; Copyright (C) 2009-2010 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-etags.el --- A company-mode completion back-end for etags
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (require 'etags)
diff --git a/company-files.el b/company-files.el
index bc76469..6b34d57 100644
--- a/company-files.el
+++ b/company-files.el
@@ -1,21 +1,29 @@
-;;; company-files.el --- a company-mode completion back-end for file names
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-files.el --- A company-mode completion back-end for file names
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
@@ -65,7 +73,7 @@
 
 ;;;###autoload
 (defun company-files (command &optional arg &rest ignored)
-  "a `company-mode' completion back-end existing file names."
+  "A `company-mode' completion back-end existing file names."
   (interactive (list 'interactive))
   (case command
     (interactive (company-begin-backend 'company-files))
diff --git a/company-gtags.el b/company-gtags.el
index 2630f73..62c9707 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -1,34 +1,42 @@
-;;; company-gtags.el --- a company-mode completion back-end for GNU Global
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-gtags.el --- A company-mode completion back-end for GNU Global
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
 
 (defcustom company-gtags-executable
   (executable-find "global")
-  "*Location of GNU global executable"
+  "*Location of GNU global executable."
   :type 'string
   :group 'company)
 
 (define-obsolete-variable-alias
   'company-gtags-gnu-global-program-name
-  'company-gtags-executable)
+  'company-gtags-executable "earlier")
 
 (defvar company-gtags--tags-available-p 'unknown)
 (make-variable-buffer-local 'company-gtags--tags-available-p)
diff --git a/company-ispell.el b/company-ispell.el
index c4acebc..05266af 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -1,21 +1,29 @@
-;;; company-ispell.el --- a company-mode completion back-end using ispell
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-ispell.el --- A company-mode completion back-end using ispell
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (require 'ispell)
diff --git a/company-keywords.el b/company-keywords.el
index 3efda9e..88af112 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -1,21 +1,29 @@
-;;; company-keywords.el --- a company back-end for programming language 
keywords
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-keywords.el --- A company back-end for programming language 
keywords
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
@@ -225,5 +233,3 @@
 
 (provide 'company-keywords)
 ;;; company-keywords.el ends here
-
-
diff --git a/company-nxml.el b/company-nxml.el
index 5d05bc6..0be1819 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -1,21 +1,29 @@
-;;; company-nxml.el --- a company-mode completion back-end for nxml-mode
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-nxml.el --- A company-mode completion back-end for nxml-mode
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (require 'nxml-mode)
@@ -29,8 +37,8 @@
   (replace-regexp-in-string "w" company-nxml-token-regexp
    "<w\\(?::w\\)?\
 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
-[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
-[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
+\[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
+\[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
 \\(\"\\([^\"]*\\>\\)\\|'\\([^']*\\>\\)\\)\\="
    t t))
 
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 344a8be..8d60a2e 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -1,21 +1,29 @@
-;;; company-oddmuse.el --- a company-mode completion back-end for oddmuse-mode
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-oddmuse.el --- A company-mode completion back-end for oddmuse-mode
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when 'compile (require 'yaooddmuse nil t))
diff --git a/company-pysmell.el b/company-pysmell.el
index 83dfebb..8cfe10d 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -1,21 +1,29 @@
-;;; company-pysmell.el --- a company-mode completion back-end for pysmell.el
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-pysmell.el --- A company-mode completion back-end for pysmell.el
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (eval-when-compile (require 'cl))
 (require 'pysmell)
diff --git a/company-ropemacs.el b/company-ropemacs.el
index e63a8df..2b402f7 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,21 +1,29 @@
-;;; company-ropemacs.el --- a company-mode completion back-end for pysmell.el
-;;
-;; Copyright (C) 2009-2010 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-ropemacs.el --- A company-mode completion back-end for pysmell.el
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (eval-when-compile (require 'cl))
 (require 'pymacs)
diff --git a/company-semantic.el b/company-semantic.el
index f22266d..eacf1c7 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,21 +1,29 @@
-;;; company-semantic.el --- a company-mode back-end using CEDET Semantic
-;;
-;; Copyright (C) 2009-2010 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-semantic.el --- A company-mode back-end using CEDET Semantic
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (or (require 'semantic-analyze nil t)
@@ -30,7 +38,7 @@
 (defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
 
 (defvar company-semantic--current-tags nil
-  "Tags for the current context")
+  "Tags for the current context.")
 
 (defun company-semantic-doc-or-summary (tag)
   (or (semantic-documentation-for-tag tag)
@@ -110,7 +118,7 @@ Symbols are chained by \".\" or \"->\"."
                    (assoc arg company-semantic--current-tags)))
     (doc-buffer (company-semantic-doc-buffer
                  (assoc arg company-semantic--current-tags)))
-    ;; because "" is an empty context and doesn't return local variables
+    ;; Because "" is an empty context and doesn't return local variables.
     (no-cache (equal arg ""))
     (location (let ((tag (assoc arg company-semantic--current-tags)))
                 (when (buffer-live-p (semantic-tag-buffer tag))
diff --git a/company-template.el b/company-template.el
index f9b0fcd..53d9687 100644
--- a/company-template.el
+++ b/company-template.el
@@ -1,3 +1,26 @@
+;;; company-template.el
+
+;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
 (eval-when-compile (require 'cl))
 
 (defface company-template-field
diff --git a/company-tempo.el b/company-tempo.el
index efba482..1dda49e 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -1,21 +1,29 @@
-;;; company-tempo.el --- a company-mode completion back-end for tempo
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-tempo.el --- A company-mode completion back-end for tempo
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
diff --git a/company-xcode.el b/company-xcode.el
index 884a78d..42e00de 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -1,27 +1,35 @@
-;;; company-xcode.el --- a company-mode completion back-end for Xcode projects
-;;
-;; Copyright (C) 2009 Nikolaj Schumacher
-;;
-;; This file is part of company 0.5.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+;;; company-xcode.el --- A company-mode completion back-end for Xcode projects
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
 
 (require 'company)
 (eval-when-compile (require 'cl))
 
 (defcustom company-xcode-xcodeindex-executable (executable-find "xcodeindex")
-  "*Location of xcodeindex executable"
+  "*Location of xcodeindex executable."
   :group 'company-xcode
   :type 'file)
 
@@ -35,7 +43,7 @@
 (defcustom company-xcode-types
   '("Class" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
     "Type" "Union" "Function")
-  "*The types of symbols offered by `company-xcode'
+  "*The types of symbols offered by `company-xcode'.
 No context-enabled completion is available.  Types like methods will be
 offered regardless of whether the class supports them.  The defaults should be
 valid in most contexts."
diff --git a/company.el b/company.el
index 317e1a7..142ecab 100644
--- a/company.el
+++ b/company.el
@@ -1,28 +1,28 @@
-;;; company.el --- extensible inline text completion mechanism
-;;
-;; Copyright (C) 2009-2010 Nikolaj Schumacher
-;;
-;; Author: Nikolaj Schumacher <bugs * nschum de>
+;;; company.el --- Extensible inline text completion mechanism
+
+;; Copyright (C) 2009-2011  Free Software Foundation, Inc.
+
+;; Author: Nikolaj Schumacher
 ;; Version: 0.5
 ;; Keywords: abbrev, convenience, matching
-;; URL: http://nschum.de/src/emacs/company/
+;; URL: http://nschum.de/src/emacs/company-mode/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
-;;
-;; This file is NOT part of GNU Emacs.
-;;
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License
-;; as published by the Free Software Foundation; either version 2
-;; of the License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful,
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
-;;
+
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
-;;
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
 ;;; Commentary:
 ;;
 ;; Company is a modular completion mechanism.  Modules for retrieving 
completion
@@ -65,6 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-capf': completion adapter using
+;;    `completion-at-point-functions'.  (Stefan Monnier)
 ;;    Switching tags now works correctly in `company-etags'.
 ;;
 ;; 2010-02-24 (0.5)
@@ -134,7 +136,7 @@
 ;;
 ;; 2009-03-20 (0.1)
 ;;    Initial release.
-;;
+
 ;;; Code:
 
 (eval-when-compile (require 'cl))
@@ -309,7 +311,29 @@ If this many lines are not available, prefer to display 
the tooltip above."
                         (assq backend company-safe-backends))
                 (return t))))))
 
-(defcustom company-backends '(company-elisp company-nxml company-css
+(defun company-capf (command &optional arg &rest args)
+  "Adapter for Company completion to use `completion-at-point-functions'."
+  (interactive (list 'interactive))
+  (case command
+    (interactive (company-begin-backend 'company-capf))
+    (prefix
+     (let ((res (run-hook-wrapped 'completion-at-point-functions
+                                  ;; Ignore misbehaving functions.
+                                  #'completion--capf-wrapper 'optimist)))
+       (when (consp res)
+         (if (> (nth 1 res) (point))
+             'stop
+           (buffer-substring-no-properties (nth 0 res) (point))))))
+    (candidates
+     (let ((res (run-hook-wrapped 'completion-at-point-functions
+                                  ;; Ignore misbehaving functions.
+                                  #'completion--capf-wrapper 'optimist)))
+       (when (consp res)
+         (all-completions arg (nth 2 res)
+                          (plist-get (nthcdr 3 res) :predicate)))))))
+
+(defcustom company-backends '(;; company-capf ;FIXME: Untested!
+                              company-elisp company-nxml company-css
                               company-eclim company-semantic company-clang
                               company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
@@ -327,7 +351,7 @@ Each back-end is a function that takes a variable number of 
arguments.
 The first argument is the command requested from the back-end.  It is one
 of the following:
 
-'prefix: The back-end should return the text to be completed.  It must be
+`prefix': The back-end should return the text to be completed.  It must be
 text immediately before `point'.  Returning nil passes control to the next
 back-end.  The function should return 'stop if it should complete but cannot
 \(e.g. if it is in the middle of a string\).  If the returned value is only
@@ -335,33 +359,33 @@ part of the prefix (e.g. the part after \"->\" in C), the 
back-end may return a
 cons of prefix and prefix length, which is then used in the
 `company-minimum-prefix-length' test.
 
-'candidates: The second argument is the prefix to be completed.  The
+`candidates': The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.
 
 Optional commands:
 
-'sorted: The back-end may return t here to indicate that the candidates
+`sorted': The back-end may return t here to indicate that the candidates
 are sorted and will not need to be sorted again.
 
-'duplicates: If non-nil, company will take care of removing duplicates
+`duplicates': If non-nil, company will take care of removing duplicates
 from the list.
 
-'no-cache: Usually company doesn't ask for candidates again as completion
+`no-cache': Usually company doesn't ask for candidates again as completion
 progresses, unless the back-end returns t for this command.  The second
 argument is the latest prefix.
 
-'meta: The second argument is a completion candidate.  The back-end should
+`meta': The second argument is a completion candidate.  The back-end should
 return a (short) documentation string for it.
 
-'doc-buffer: The second argument is a completion candidate.  The back-end 
should
-create a buffer (preferably with `company-doc-buffer'), fill it with
-documentation and return it.
+`doc-buffer': The second argument is a completion candidate.
+The back-end should create a buffer (preferably with `company-doc-buffer'),
+fill it with documentation and return it.
 
-'location: The second argument is a completion candidate.  The back-end can
+`location': The second argument is a completion candidate.  The back-end can
 return the cons of buffer and buffer location, or of file and line
 number where the completion candidate was defined.
 
-'require-match: If this value is t, the user is not allowed to enter anything
+`require-match': If this value is t, the user is not allowed to enter anything
 not offering as a candidate.  Use with care!  The default value nil gives the
 user that choice with `company-require-match'.  Return value 'never overrides
 that option the other way around.

commit ffdeedf11ae57e976c8bc164ebfdcf1aff869a74
Author: Leo Liu <address@hidden>
Date:   Fri Mar 8 18:39:19 2013 +0800

    Fix #1: use path-separator instead

diff --git a/ggtags.el b/ggtags.el
index d3f13a4..601f466 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -105,7 +105,8 @@ Return -1 if it does not exist."
       -1)))
 
 (defun ggtags-get-libpath ()
-  (split-string (or (getenv "GTAGSLIBPATH") "") ":" t))
+  (split-string (or (getenv "GTAGSLIBPATH") "")
+                (regexp-quote path-separator) t))
 
 (defun ggtags-cache-get (key)
   (assoc key ggtags-cache))

commit f713d6fb3b46417d500d2836d9b6aa8df2093e54
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 20:12:12 2013 +0400

    * js2-multiline-decl-indentation: Simplify a logical condition

diff --git a/js2-mode.el b/js2-mode.el
index c8d56a3..10655c5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9593,11 +9593,10 @@ to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
                         (js2-backward-sws)
                         (or (eq (char-before) ?,)
                             (and (not (eq (char-before) ?\;))
-                                 (and
-                                  (prog2 (skip-syntax-backward ".")
-                                      (looking-at js2-indent-operator-re)
-                                    (js2-backward-sws))
-                                  (not (eq (char-before) ?\;))))
+                                 (prog2 (skip-syntax-backward ".")
+                                     (looking-at js2-indent-operator-re)
+                                   (js2-backward-sws))
+                                 (not (eq (char-before) ?\;)))
                             (js2-same-line pos)))))
           (condition-case err
               (backward-sexp)

commit 38585ff9eaf38ed0f38cccd9b8943204ee059652
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 06:22:39 2013 +0400

    emacs -l doesn't handle wilcards

diff --git a/Makefile b/Makefile
index 6d05248..36f2cb9 100644
--- a/Makefile
+++ b/Makefile
@@ -20,4 +20,5 @@ js2-imenu-extras.elc: js2-mode.elc
        emacs $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el
 
 test:
-       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/*.el -f ert-run-tests-batch
+       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/parser.el\
+         -l tests/indent.el -f ert-run-tests-batch

commit fd16a6299ece3b9b0c85aaa1b48ffbdf56541270
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 06:19:16 2013 +0400

    Update Makefile

diff --git a/Makefile b/Makefile
index 3ff3d8c..6d05248 100644
--- a/Makefile
+++ b/Makefile
@@ -20,4 +20,4 @@ js2-imenu-extras.elc: js2-mode.elc
        emacs $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el
 
 test:
-       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/ast.el -f 
ert-run-tests-batch
+       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/*.el -f ert-run-tests-batch
diff --git a/tests/indent.el b/tests/indent.el
index d363374..b0d1b31 100644
--- a/tests/indent.el
+++ b/tests/indent.el
@@ -13,7 +13,8 @@
 (defmacro* js2-deftest-indent (name content &key bind)
   `(ert-deftest ,name ()
      (let ,(append '((js2-basic-offset 2)
-                     (js2-pretty-multiline-declarations t))
+                     (js2-pretty-multiline-declarations t)
+                     (inhibit-point-motion-hooks t))
                    bind)
        (js2-test-indent ,content))))
 

commit 1c3b98ac36bda12408d94b27092dc3b47e647593
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 06:15:18 2013 +0400

    Fix #89

diff --git a/js2-mode.el b/js2-mode.el
index d48505c..c8d56a3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130228
+;; Version: 20130307
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 
@@ -9594,7 +9594,7 @@ to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
                         (or (eq (char-before) ?,)
                             (and (not (eq (char-before) ?\;))
                                  (and
-                                  (prog2 (skip-chars-backward "[[:punct:]]")
+                                  (prog2 (skip-syntax-backward ".")
                                       (looking-at js2-indent-operator-re)
                                     (js2-backward-sws))
                                   (not (eq (char-before) ?\;))))
diff --git a/tests/indent.el b/tests/indent.el
index f09734e..d363374 100644
--- a/tests/indent.el
+++ b/tests/indent.el
@@ -7,7 +7,8 @@
       (insert (replace-regexp-in-string "^ *" "" s))
       (js2-mode)
       (indent-region (point-min) (point-max))
-      (should (string= s (buffer-substring (point-min) (point)))))))
+      (should (string= s (buffer-substring-no-properties
+                          (point-min) (point)))))))
 
 (defmacro* js2-deftest-indent (name content &key bind)
   `(ert-deftest ,name ()
@@ -39,6 +40,10 @@
   "var foo = 100500 /
   |      16;")
 
+(js2-deftest-indent no-multiline-decl-with-operator-inside-string
+  "var foo = bar('/protocols/')
+  |baz()")
+
 (js2-deftest-indent no-multiline-decl-implicit-semicolon
   "var foo = 100500
   |1")

commit aebd60c8865fd914e45a05f1ac5ad86988404e04
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 06:09:18 2013 +0400

    Add some indentation tests

diff --git a/tests/indent.el b/tests/indent.el
new file mode 100644
index 0000000..f09734e
--- /dev/null
+++ b/tests/indent.el
@@ -0,0 +1,69 @@
+(require 'ert)
+(require 'js2-mode)
+
+(defun js2-test-indent (content)
+  (let ((s (replace-regexp-in-string "^ *|" "" content)))
+    (with-temp-buffer
+      (insert (replace-regexp-in-string "^ *" "" s))
+      (js2-mode)
+      (indent-region (point-min) (point-max))
+      (should (string= s (buffer-substring (point-min) (point)))))))
+
+(defmacro* js2-deftest-indent (name content &key bind)
+  `(ert-deftest ,name ()
+     (let ,(append '((js2-basic-offset 2)
+                     (js2-pretty-multiline-declarations t))
+                   bind)
+       (js2-test-indent ,content))))
+
+(put 'js2-deftest-indent 'lisp-indent-function 'defun)
+
+(js2-deftest-indent no-multiline-decl-indent-after-semicolon
+  "var foo = 1;
+  |bar = 2")
+
+(js2-deftest-indent multiline-decl-indent-after-comma
+  "let foo = 1,
+  |    bar = 2")
+
+(js2-deftest-indent no-multiline-decl-when-disabled
+  "let foo = 1,
+  |bar = 2"
+  :bind ((js2-pretty-multiline-declarations nil)))
+
+(js2-deftest-indent multiline-decl-with-continued-expr
+  "var foo = 100500
+  |      + 1")
+
+(js2-deftest-indent multiline-decl-with-continued-expr-same-line
+  "var foo = 100500 /
+  |      16;")
+
+(js2-deftest-indent no-multiline-decl-implicit-semicolon
+  "var foo = 100500
+  |1")
+
+(js2-deftest-indent multiline-decl-sees-keyword-width
+  "const foo = 1,
+  |      bar = 2;")
+
+(js2-deftest-indent multiline-decl-second-arg-value-parenthesised
+  "var foo = 1,
+  |    bar = [
+  |      1, 2,
+  |      3, 4
+  |    ],
+  |    baz = 5;")
+
+(js2-deftest-indent multiline-decl-first-arg-function-normal
+  "var foo = function() {
+  |  return 7;
+  |},
+  |    bar = 8;")
+
+(js2-deftest-indent multiline-decl-first-arg-function-indent-all
+  "var foo = function() {
+  |      return 7;
+  |    },
+  |    bar = 8;"
+  :bind ((js2-pretty-multiline-declarations 'all)))

commit 5309fdede51856423e09f3af021e01876c286109
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 7 05:33:33 2013 +0400

    tests{ast -> parser}.el

diff --git a/tests/ast.el b/tests/parser.el
similarity index 62%
rename from tests/ast.el
rename to tests/parser.el
index 1611049..00b7cff 100644
--- a/tests/ast.el
+++ b/tests/parser.el
@@ -9,7 +9,7 @@
     (should (null js2-mode-buffer-dirty-p))
     js2-mode-ast))
 
-(defun js2-test-ast-string (code-string &key syntax-error)
+(defun js2-test-parse-string (code-string &key syntax-error)
   (let ((ast (js2-test-string-to-ast code-string)))
     (if syntax-error
         (let ((errors (js2-ast-root-errors ast)))
@@ -24,7 +24,7 @@
         (should (string= code-string (buffer-substring-no-properties
                                       (point-min) (point))))))))
 
-(defmacro* js2-deftest-ast (name code-string &key bind syntax-error)
+(defmacro* js2-deftest-parse (name code-string &key bind syntax-error)
   "Parse CODE-STRING.  If SYNTAX-ERROR is nil, print syntax tree
 with `js2-print-tree' and assert the result to be equal to the
 original string.  If SYNTAX-ERROR is passed, expect syntax error
@@ -32,82 +32,82 @@ highlighting substring equal to SYNTAX-ERROR value.
 BIND defines bindings to apply them around the test."
   `(ert-deftest ,name ()
      (let ,(append bind '((js2-basic-offset 2)))
-       (js2-test-ast-string ,code-string :syntax-error ,syntax-error))))
+       (js2-test-parse-string ,code-string :syntax-error ,syntax-error))))
 
-(put 'js2-deftest-ast 'lisp-indent-function 'defun)
+(put 'js2-deftest-parse 'lisp-indent-function 'defun)
 
 ;;; Callers of `js2-valid-prop-name-token'.
 
-(js2-deftest-ast parse-property-access-when-not-keyword
+(js2-deftest-parse parse-property-access-when-not-keyword
   "A.foo = 3;")
 
-(js2-deftest-ast parse-property-access-when-keyword
+(js2-deftest-parse parse-property-access-when-keyword
   "A.in = 3;"
   :bind ((js2-allow-keywords-as-property-names t)))
 
-(js2-deftest-ast parse-property-access-when-keyword-no-xml
+(js2-deftest-parse parse-property-access-when-keyword-no-xml
   "A.in = 3;"
   :bind ((js2-allow-keywords-as-property-names t)
          (js2-compiler-xml-available nil)))
 
-(js2-deftest-ast parse-array-literal-when-not-keyword
+(js2-deftest-parse parse-array-literal-when-not-keyword
   "a = {b: 1};")
 
-(js2-deftest-ast parse-array-literal-when-keyword
+(js2-deftest-parse parse-array-literal-when-keyword
   "a = {in: 1};"
   :bind ((js2-allow-keywords-as-property-names t)))
 
 ;;; 'of' contextual keyword.
 
-(js2-deftest-ast parse-array-comp-loop-with-of
+(js2-deftest-parse parse-array-comp-loop-with-of
   "[a for (a of [])];")
 
-(js2-deftest-ast parse-for-of
+(js2-deftest-parse parse-for-of
   "for (var a of []) {\n}")
 
-(js2-deftest-ast of-can-be-var-name
+(js2-deftest-parse of-can-be-var-name
   "var of = 3;")
 
-(js2-deftest-ast of-can-be-function-name
+(js2-deftest-parse of-can-be-function-name
   "function of() {\n}")
 
 ;;; Destructuring binding.
 
-(js2-deftest-ast destruct-in-declaration
+(js2-deftest-parse destruct-in-declaration
   "var {a, b} = {a: 1, b: 2};")
 
-(js2-deftest-ast destruct-in-arguments
+(js2-deftest-parse destruct-in-arguments
   "function f({a: aa, b: bb}) {\n}")
 
-(js2-deftest-ast destruct-in-array-comp-loop
+(js2-deftest-parse destruct-in-array-comp-loop
   "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
 
-(js2-deftest-ast destruct-in-catch-clause
+(js2-deftest-parse destruct-in-catch-clause
   "try {\n} catch ({a, b}) {\n  a + b;\n}")
 
 ;;; Function parameters.
 
-(js2-deftest-ast function-with-default-parameters
+(js2-deftest-parse function-with-default-parameters
   "function foo(a = 1, b = a + 1) {\n}")
 
-(js2-deftest-ast function-with-no-default-after-default
+(js2-deftest-parse function-with-no-default-after-default
   "function foo(a = 1, b) {\n}"
   :syntax-error "b")
 
-(js2-deftest-ast function-with-destruct-after-default
+(js2-deftest-parse function-with-destruct-after-default
   "function foo(a = 1, {b, c}) {\n}"
   :syntax-error "{")
 
-(js2-deftest-ast function-with-rest-parameter
+(js2-deftest-parse function-with-rest-parameter
   "function foo(a, b, ...rest) {\n}")
 
-(js2-deftest-ast function-with-param-after-rest-parameter
+(js2-deftest-parse function-with-param-after-rest-parameter
   "function foo(a, ...b, rest) {\n}"
   :syntax-error "rest")
 
-(js2-deftest-ast function-with-destruct-after-rest-parameter
+(js2-deftest-parse function-with-destruct-after-rest-parameter
   "function foo(a, ...b, {}) {\n}"
   :syntax-error "{}")
 
-(js2-deftest-ast function-with-rest-after-default-parameter
+(js2-deftest-parse function-with-rest-after-default-parameter
   "function foo(a = 1, ...rest) {\n}")

commit a28e0c3b186c123b158749de2d38815757d20962
Author: Leo Liu <address@hidden>
Date:   Fri Mar 1 12:58:53 2013 +0800

    Make use of the new switch --path-style to global

diff --git a/ggtags.el b/ggtags.el
index d5a4037..d3f13a4 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -79,6 +79,14 @@ If nil, use Emacs default."
        (progn ,@body)
      (file-error nil)))
 
+;; http://thread.gmane.org/gmane.comp.gnu.global.bugs/1518
+(defvar ggtags-global-has-path-style    ; introduced in global 6.2.8
+  (ggtags-ignore-file-error
+    (and (string-match-p "^--path-style "
+                         (shell-command-to-string "global --help"))
+         t))
+  "Non-nil if `global' supports --path-style switch.")
+
 (defmacro ggtags-ensure-global-buffer (&rest body)
   (declare (indent 0))
   `(progn
@@ -185,6 +193,11 @@ Return -1 if it does not exist."
              (format (if default "Tag (default %s): " "Tag: ") default)
              tags nil t nil nil default)))))
 
+(defvar ggtags-global-options
+  (concat "-v --result=grep"
+          (and ggtags-global-has-path-style " --path-style=shorter"))
+  "Options (as a string) for running `global'.")
+
 ;;;###autoload
 (defun ggtags-find-tag (name &optional verbose)
   "Find definitions or references to tag NAME by context.
@@ -200,11 +213,13 @@ When called with prefix, ask the name and kind of tag."
         (default-directory (ggtags-root-directory)))
     (compilation-start
      (if verbose
-         (format "global -v%s --result=grep \"%s\""
+         (format "global %s %s \"%s\""
+                 ggtags-global-options
                  (if (y-or-n-p "Kind (y for definition n for reference)? ")
-                     "" "r")
+                     "" "-r")
                  name)
-       (format "global -v --result=grep --from-here=%d:%s \"%s\""
+       (format "global %s --from-here=%d:%s \"%s\""
+               ggtags-global-options
                (line-number-at-pos)
                (expand-file-name buffer-file-name)
                name))

commit 63f135e2bafcb6dfd9a8014045f8e89d46e2f707
Author: Dmitry Gutov <address@hidden>
Date:   Thu Feb 28 11:38:33 2013 +0400

    * js2-mode-forward-sexp: never jump over an unbalanced paren
    
    Fixes #78

diff --git a/js2-mode.el b/js2-mode.el
index a21d3f7..d48505c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130227
+;; Version: 20130228
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 
@@ -10925,7 +10925,7 @@ move backward across N balanced expressions."
   (save-restriction
     (widen) ;; `blink-matching-open' calls `narrow-to-region'
     (js2-reparse))
-  (let ((scan-msg "Containing expression ends prematurely")
+  (let (forward-sexp-function
         node (start (point)) pos lp rp child)
     (cond
      ;; backward-sexp
@@ -10936,22 +10936,26 @@ move backward across N balanced expressions."
      ((and arg (minusp arg))
       (dotimes (i (- arg))
         (js2-backward-sws)
-        (forward-char -1)  ; enter the node we backed up to
+        (forward-char -1)   ; Enter the node we backed up to.
         (when (setq node (js2-node-at-point (point) t))
           (setq pos (js2-node-abs-pos node))
           (let ((parens (js2-mode-forward-sexp-parens node pos)))
             (setq lp (car parens)
-                  rp (cdr parens))))
-        (goto-char
-         (or (when (and lp (> start lp))
-               (if (and rp (<= start rp))
-                   (if (setq child (js2-node-closest-child node (point) lp t))
-                       (js2-node-abs-pos child)
-                     (goto-char start)
-                     (signal 'scan-error (list scan-msg lp lp)))
-                 lp))
-             pos
-             (point-min)))))
+                  rp (cdr parens)))
+          (when (and lp (> start lp))
+            (if (and rp (<= start rp))
+                ;; Between parens, check if there's a child node we can jump.
+                (when (setq child (js2-node-closest-child node (point) lp t))
+                  (setq pos (js2-node-abs-pos child)))
+              ;; Before both parens.
+              (setq pos lp)))
+          (let ((state (parse-partial-sexp start pos)))
+            (goto-char (if (not (zerop (car state)))
+                           ;; Stumble at the unbalanced paren if < 0, or
+                           ;; jump a bit further if > 0.
+                           (scan-sexps start -1)
+                         pos))))
+        (unless pos (goto-char (point-min)))))
      (t
       ;; forward-sexp
       (dotimes (i arg)
@@ -10960,25 +10964,27 @@ move backward across N balanced expressions."
           (setq pos (js2-node-abs-pos node))
           (let ((parens (js2-mode-forward-sexp-parens node pos)))
             (setq lp (car parens)
-                  rp (cdr parens))))
-        (goto-char
-         (or (when (and rp (<= start rp))
-               (if (> start lp)
-                   (if (setq child (js2-node-closest-child node (point) rp))
-                       (js2-node-abs-end child)
-                     (goto-char start)
-                     (signal 'scan-error (list scan-msg rp (1+ rp))))
-                 (1+ rp)))
-             (and pos
-                  (+ pos
-                     (js2-node-len
+                  rp (cdr parens)))
+          (or
+           (when (and rp (<= start rp))
+             (if (> start lp)
+                 (when (setq child (js2-node-closest-child node (point) rp))
+                   (setq pos (js2-node-abs-end child)))
+               (setq pos (1+ rp))))
+           ;; No parens or child nodes, looks for the end of the curren node.
+           (incf pos (js2-node-len
                       (if (js2-expr-stmt-node-p (js2-node-parent node))
-                          ;; stop after the semicolon
+                          ;; Stop after the semicolon.
                           (js2-node-parent node)
                         node))))
-             (point-max))))))))
+          (let ((state (save-excursion (parse-partial-sexp start pos))))
+            (goto-char (if (not (zerop (car state)))
+                           (scan-sexps start 1)
+                         pos))))
+        (unless pos (goto-char (point-max))))))))
 
 (defun js2-mode-forward-sexp-parens (node abs-pos)
+  "Return a cons cell with positions of main parens in NODE."
   (cond
    ((or (js2-array-node-p node)
         (js2-object-node-p node)

commit 3eb2651ce2ddff6f2dc83720eb15ba2617457b94
Author: Dmitry Gutov <address@hidden>
Date:   Thu Feb 28 01:02:16 2013 +0400

    Fix js2-node-[lr]p for js2-paren-node

diff --git a/js2-mode.el b/js2-mode.el
index 44411ab..a21d3f7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4162,7 +4162,7 @@ Note that the position may be nil in the case of a parse 
error."
    ((js2-call-node-p node)
     (js2-call-node-lp node))
    ((js2-paren-node-p node)
-    (js2-node-pos node))
+    0)
    ((js2-switch-node-p node)
     (js2-switch-node-lp node))
    ((js2-catch-node-p node)
@@ -4197,7 +4197,7 @@ Note that the position may be nil in the case of a parse 
error."
    ((js2-call-node-p node)
     (js2-call-node-rp node))
    ((js2-paren-node-p node)
-    (+ (js2-node-pos node) (js2-node-len node)))
+    (1- (js2-node-len node)))
    ((js2-switch-node-p node)
     (js2-switch-node-rp node))
    ((js2-catch-node-p node)
@@ -10954,7 +10954,6 @@ move backward across N balanced expressions."
              (point-min)))))
      (t
       ;; forward-sexp
-      (js2-forward-sws)
       (dotimes (i arg)
         (js2-forward-sws)
         (when (setq node (js2-node-at-point (point) t))

commit 02f64d8bb616c81ff1c422c8130097a712ad559b
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 27 03:19:58 2013 +0400

    Remove some of the unused definitions

diff --git a/js2-mode.el b/js2-mode.el
index 091e00b..44411ab 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130219
+;; Version: 20130227
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 
@@ -1952,12 +1952,6 @@ Returns nil if element is not found in the list."
   (and (>= pos (point-at-bol))
        (<= pos (point-at-eol))))
 
-(defun js2-same-line-2 (p1 p2)
-  "Return t if P1 is on the same line as P2."
-  (save-excursion
-    (goto-char p1)
-    (js2-same-line p2)))
-
 (defun js2-code-bug ()
   "Signal an error when we encounter an unexpected code path."
   (error "failed assertion"))
@@ -2186,12 +2180,6 @@ If any given node in NODES is nil, doesn't record that 
link."
 (put 'cl-struct-js2-scope 'js2-visitor 'js2-visit-block)
 (put 'cl-struct-js2-scope 'js2-printer 'js2-print-none)
 
-(defun js2-scope-set-parent-scope (scope parent)
-  (setf (js2-scope-parent-scope scope) parent
-        (js2-scope-top scope) (if (null parent)
-                                  scope
-                                (js2-scope-top parent))))
-
 (defun js2-node-get-enclosing-scope (node)
   "Return the innermost `js2-scope' node surrounding NODE.
 Returns nil if there is no enclosing scope node."
@@ -4072,18 +4060,6 @@ If N has no parent pointer, returns N."
         (js2-node-root parent)
       n)))
 
-(defun js2-node-position-in-parent (node &optional parent)
-  "Return the position of NODE in parent's block-kids list.
-PARENT can be supplied if known.  Positioned returned is zero-indexed.
-Returns 0 if NODE is not a child of a block statement, or if NODE
-is not a statement node."
-  (let ((p (or parent (js2-node-parent node)))
-        (i 0))
-    (if (not (js2-block-node-p p))
-        i
-      (or (js2-position node (js2-block-node-kids p))
-          0))))
-
 (defsubst js2-node-short-name (n)
   "Return the short name of node N as a string, e.g. `js2-if-node'."
   (substring (symbol-name (aref n 0))
@@ -4488,25 +4464,6 @@ If NODE is the ast-root, returns nil."
       (setq node (js2-node-parent node)))
     node))
 
-(defun js2-nested-function-p (node)
-  "Return t if NODE is a nested function, or is inside a nested function."
-  (unless (js2-ast-root-p node)
-    (js2-function-node-p (if (js2-function-node-p node)
-                             (js2-node-parent-script-or-fn node)
-                           (js2-node-parent-script-or-fn
-                            (js2-node-parent-script-or-fn node))))))
-
-(defun js2-mode-shift-kids (kids start offset)
-  (dolist (kid kids)
-    (if (> (js2-node-pos kid) start)
-        (incf (js2-node-pos kid) offset))))
-
-(defun js2-mode-shift-children (parent start offset)
-  "Update start-positions of all children of PARENT beyond START."
-  (let ((root (js2-node-root parent)))
-    (js2-mode-shift-kids (js2-node-child-list parent) start offset)
-    (js2-mode-shift-kids (js2-ast-root-comments root) start offset)))
-
 (defun js2-node-is-descendant (node ancestor)
   "Return t if NODE is a descendant of ANCESTOR."
   (while (and node
@@ -4661,28 +4618,6 @@ You should use `js2-print-tree' instead of this 
function."
        (t
         (aref js2-side-effecting-tokens tt))))))
 
-(defun js2-member-expr-leftmost-name (node)
-  "For an expr such as foo.bar.baz, return leftmost node foo.
-NODE is any `js2-node' object.  If it represents a member expression,
-which is any sequence of property gets, element-gets, function calls,
-or xml descendants/filter operators, then we look at the lexically
-leftmost (first) node in the chain.  If it is a name-node we return it.
-Note that NODE can be a raw name-node and it will be returned as well.
-If NODE is not a name-node or member expression, or if it is a member
-expression whose leftmost target is not a name node, returns nil."
-  (let ((continue t)
-        result)
-    (while (and continue (not result))
-      (cond
-       ((js2-name-node-p node)
-        (setq result node))
-       ((js2-prop-get-node-p node)
-        (setq node (js2-prop-get-node-left node)))
-       ;; TODO:  handle call-nodes, xml-nodes, others?
-       (t
-        (setq continue nil))))
-    result))
-
 (defconst js2-stmt-node-types
   (list js2-BLOCK
         js2-BREAK
@@ -6032,10 +5967,6 @@ corresponding number.  Otherwise return -1."
       (js2-xml-discard-string)
       nil)))
 
-(defun js2-scanner-get-line ()
-  "Return the text of the current scan line."
-  (buffer-substring (point-at-bol) (point-at-eol)))
-
 ;;; Highlighting
 
 (defun js2-set-face (beg end face &optional record)
@@ -6049,19 +5980,6 @@ corresponding number.  Otherwise return -1."
         (push (list beg end face) js2-mode-fontifications)
       (put-text-property beg end 'font-lock-face face))))
 
-(defun js2-set-kid-face (pos kid len face)
-  "Set-face on a child node.
-POS is absolute buffer position of parent.
-KID is the child node.
-LEN is the length to fontify.
-FACE is the face to fontify with."
-  (js2-set-face (+ pos (js2-node-pos kid))
-                (+ pos (js2-node-pos kid) (js2-node-len kid))
-                face))
-
-(defsubst js2-fontify-kwd (start length)
-  (js2-set-face start (+ start length) 'font-lock-keyword-face))
-
 (defsubst js2-clear-face (beg end)
   (remove-text-properties beg end '(font-lock-face nil
                                     help-echo nil
@@ -9887,14 +9805,6 @@ If POS is non-nil, go to that point and return 
indentation for that line."
     (skip-chars-forward " \t")
     (looking-at "case\\s-.+:")))
 
-(defun js2-syntax-bol ()
-  "Return the point at the first non-whitespace char on the line.
-Returns `point-at-bol' if the line is empty."
-  (save-excursion
-    (beginning-of-line)
-    (skip-chars-forward " \t")
-    (point)))
-
 (defun js2-bounce-indent (normal-col parse-status &optional backwards)
   "Cycle among alternate computed indentation positions.
 PARSE-STATUS is the result of `parse-partial-sexp' from the beginning
@@ -10711,48 +10621,6 @@ Also moves past comment delimiters when inside 
comments."
       (skip-chars-backward " \t")
     (goto-char (point-at-eol))))
 
-(defsubst js2-mode-inside-string ()
-  "Return non-nil if inside a string.
-Actually returns the quote character that begins the string."
-  (nth 3 (syntax-ppss)))
-
-(defun js2-mode-inside-comment-or-string ()
-  "Return non-nil if inside a comment or string."
-  (or
-   (let ((comment-start
-          (save-excursion
-            (goto-char (point-at-bol))
-            (if (re-search-forward "//" (point-at-eol) t)
-                (match-beginning 0)))))
-     (and comment-start
-          (<= comment-start (point))))
-   (let ((parse-state (syntax-ppss)))
-     (or (nth 3 parse-state)
-         (nth 4 parse-state)))))
-
-
-(defun js2-insert-catch-skel (try-pos)
-  "Complete a try/catch block after inserting a { following a try keyword.
-Rationale is that a try always needs a catch or a finally, and the catch is
-the more likely of the two.
-
-TRY-POS is the buffer position of the try keyword.  The open-curly should
-already have been inserted."
-  (insert "{")
-  (let ((try-col (save-excursion
-                   (goto-char try-pos)
-                   (current-column))))
-    (insert "\n")
-    (undo-boundary)
-    (js2-indent-line) ;; indent the blank line where cursor will end up
-    (save-excursion
-      (insert "\n")
-      (indent-to try-col)
-      (insert "} catch (x) {\n\n")
-      (indent-to try-col)
-      (insert "}"))))
-
-
 (defun js2-mode-wait-for-parse (callback)
   "Invoke CALLBACK when parsing is finished.
 If parsing is already finished, calls CALLBACK immediately."

commit 67738bd56bdf9e3c3cd89bef68c4d4a11b220719
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 27 01:36:30 2013 +0400

    Fix #87

diff --git a/js2-mode.el b/js2-mode.el
index f10019e..091e00b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9707,6 +9707,8 @@ statement without braces, else returns nil."
                      (skip-chars-backward " \t" (point-at-bol)))
                    (let ((pt (point)))
                      (back-to-indentation)
+                     (when (looking-at "}[ \t]*")
+                       (goto-char (match-end 0)))
                      (and (looking-at js2-possibly-braceless-keywords-re)
                           (= (match-end 0) pt)
                           (not (js2-end-of-do-while-loop-p))))))

commit e90d7c659dd4531185c78dacf376241de32fa7d1
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 27 00:00:03 2013 +0400

    js2-insert-and-indent was unused

diff --git a/js2-mode.el b/js2-mode.el
index 1aa1d72..f10019e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9529,29 +9529,6 @@ of continued expressions.")
   (regexp-opt '("var" "let" "const") 'words)
   "Regular expression matching variable declaration keywords.")
 
-;; This function has horrible results if you're typing an array
-;; such as [[1, 2], [3, 4], [5, 6]].  Bounce indenting -really- sucks
-;; in conjunction with electric-indent, so just disabling it.
-(defsubst js2-code-at-bol-p ()
-  "Return t if the first character on line is non-whitespace."
-  nil)
-
-(defun js2-insert-and-indent (key)
-  "Run command bound to KEY and indent current line.
-Runs the command bound to KEY in the global keymap and indents
-the current line."
-  (interactive (list (this-command-keys)))
-  (let ((cmd (lookup-key (current-global-map) key)))
-    (if (commandp cmd)
-        (call-interactively cmd)))
-  ;; don't do the electric keys inside comments or strings,
-  ;; and don't do bounce-indent with them.
-  (let ((parse-state (syntax-ppss (point)))
-        (js2-bounce-indent-p (js2-code-at-bol-p)))
-    (unless (or (nth 3 parse-state)
-                (nth 4 parse-state))
-      (indent-according-to-mode))))
-
 (defun js2-re-search-forward-inner (regexp &optional bound count)
   "Auxiliary function for `js2-re-search-forward'."
   (let (parse saved-point)

commit 81ecc1dde62a4ed0c914ee206b0bf891e6425960
Author: Leo Liu <address@hidden>
Date:   Tue Feb 26 01:44:57 2013 +0800

    Fix #1: work around bug http://debbugs.gnu.org/13811

diff --git a/ack.el b/ack.el
index 08e077a..e6cab60 100644
--- a/ack.el
+++ b/ack.el
@@ -237,7 +237,8 @@ This gets tacked on the end of the generated expressions.")
   (let ((ack (or (car (split-string ack-command nil t)) "ack")))
     (skeleton-insert `(nil ,ack " -g '(?i:" _ ")'"))))
 
-(defvar project-root)                   ; dynamically bound in `ack'
+;; Work around bug http://debbugs.gnu.org/13811
+(defvar ack--project-root nil)          ; dynamically bound in `ack'
 
 (defun ack-skel-vc-grep ()
   "Insert a template for vc grep search."
@@ -251,7 +252,7 @@ This gets tacked on the end of the generated expressions.")
          (backend (downcase (substring which 1)))
          (cmd (or (cdr (assoc which ack-vc-grep-commands))
                   (error "No command provided for `%s grep'" backend))))
-    (setq project-root root)
+    (setq ack--project-root root)
     (delete-minibuffer-contents)
     (skeleton-insert `(nil ,cmd " '" _ "'"))))
 
@@ -311,7 +312,7 @@ Otherwise, interactively choose a directory."
            (format "Run %s in `%s': "
                    (match-string-no-properties 1)
                    (file-name-nondirectory
-                    (directory-file-name project-root)))))))))
+                    (directory-file-name ack--project-root)))))))))
 
 (defun ack-minibuffer-setup-function ()
   (shell-completion-vars)
@@ -331,7 +332,7 @@ minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (let ((project-root (or (funcall ack-default-directory-function
+   (let ((ack--project-root (or (funcall ack-default-directory-function
                                     current-prefix-arg)
                            default-directory))
          ;; Disable completion cycling; see http://debbugs.gnu.org/12221
@@ -341,7 +342,7 @@ minibuffer:
                                    ack-command
                                    ack-minibuffer-local-map
                                    nil 'ack-history))
-           project-root)))
+           ack--project-root)))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))
     ;; Change to the compilation buffer so that `ack-buffer-name-function' can

commit dcfe4ddaec667cd8af1827e570bc8b428ad5428d
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 19:16:33 2013 +0400

    Use \\' instead of $

diff --git a/README.md b/README.md
index e7431f0..d66c69a 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Then put js2-mode.elc into your site-lisp directory.
 In your emacs config:
 
     (autoload 'js2-mode "js2-mode" nil t)
-    (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+    (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
 
 See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for
 additional details.
diff --git a/js2-mode.el b/js2-mode.el
index bab5bfc..1aa1d72 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -49,7 +49,7 @@
 ;;
 ;; To install it as your major mode for JavaScript editing:
 
-;;   (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+;;   (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
 
 ;; Alternately, to install it as a minor mode just for JavaScript linting,
 ;; you must add it to the appropriate major-mode hook.  Normally this would be:

commit 390b63293ed70673a840dcf52dd94041f242ca10
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 06:18:07 2013 +0400

    Bump the date

diff --git a/js2-mode.el b/js2-mode.el
index de71592..bab5bfc 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7,7 +7,7 @@
 ;;         Dmitry Gutov <address@hidden>
 ;; URL:  https://github.com/mooz/js2-mode/
 ;;       http://code.google.com/p/js2-mode/
-;; Version: 20130217
+;; Version: 20130219
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 

commit 729ef3e0cc7d1ebb0a3f0461dfa542ab24d48013
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 06:12:58 2013 +0400

    Don't include Rhino externs by default, too

diff --git a/js2-mode.el b/js2-mode.el
index 8e7d073..de71592 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -812,7 +812,7 @@ See `js2-additional-externs' for more information about 
externs."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-include-rhino-externs t
+(defcustom js2-include-rhino-externs nil
   "Non-nil to include Mozilla Rhino externs in the master externs list.
 See `js2-additional-externs' for more information about externs."
   :type 'boolean

commit ba49dd76036f659791be3fe78a093ec97da88b47
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 06:12:06 2013 +0400

    Support Node.js externs
    
    Close #86

diff --git a/js2-mode.el b/js2-mode.el
index 20fbb84..8e7d073 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -180,6 +180,13 @@ variable `js2-include-browser-externs'.")
   "Mozilla Rhino externs.
 Set `js2-include-rhino-externs' to t to include them.")
 
+(defvar js2-node-externs
+  (mapcar 'symbol-name
+          '(__dirname __filename Buffer clearInterval clearTimeout require
+            console exports global module process setInterval setTimeout))
+  "Node.js externs.
+Set `js2-include-node-externs' to t to include them.")
+
 ;;; Variables
 
 (defun js2-mark-safe-local (name pred)
@@ -791,9 +798,9 @@ These are currently only used for highlighting undeclared 
variables,
 which only worries about top-level (unqualified) references.
 As js2-mode's processing improves, we will flesh out this list.
 
-The initial value is set to `js2-ecma-262-externs', unless you
-have set `js2-include-browser-externs', in which case the browser
-externs are also included.
+The initial value is set to `js2-ecma-262-externs', unless some
+of the `js2-include-?-externs' variables are set to t, in which
+case the browser, Rhino and/or Node.js externs are also included.
 
 See `js2-additional-externs' for more information.")
 
@@ -811,6 +818,12 @@ See `js2-additional-externs' for more information about 
externs."
   :type 'boolean
   :group 'js2-mode)
 
+(defcustom js2-include-node-externs nil
+  "Non-nil to include Node.js externs in the master externs list.
+See `js2-additional-externs' for more information about externs."
+  :type 'boolean
+  :group 'js2-mode)
+
 (js2-deflocal js2-additional-externs nil
   "A buffer-local list of additional external declarations.
 It is used to decide whether variables are considered undeclared
@@ -10144,7 +10157,8 @@ highlighting features of `js2-mode'."
   (setq js2-default-externs
         (append js2-ecma-262-externs
                 (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)))
+                (if js2-include-rhino-externs js2-rhino-externs)
+                (if js2-include-node-externs js2-node-externs)))
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
       (setq js2-idle-timer-delay
@@ -10328,7 +10342,8 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
   (setq js2-default-externs
         (append js2-ecma-262-externs
                 (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-rhino-externs js2-rhino-externs)))
+                (if js2-include-rhino-externs js2-rhino-externs)
+                (if js2-include-node-externs js2-node-externs)))
 
   (setq font-lock-defaults '(nil t))
 

commit 2ac3a72df85a0827017af119da69a3102f6c28d2
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 05:51:03 2013 +0400

    js2-add-browser-externs is not defined

diff --git a/js2-mode.el b/js2-mode.el
index afc471e..20fbb84 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -801,9 +801,6 @@ See `js2-additional-externs' for more information.")
   "Non-nil to include browser externs in the master externs list.
 If you work on JavaScript files that are not intended for browsers,
 such as Mozilla Rhino server-side JavaScript, set this to nil.
-You can always include them on a per-file basis by calling
-`js2-add-browser-externs' from a function on `js2-mode-hook'.
-
 See `js2-additional-externs' for more information about externs."
   :type 'boolean
   :group 'js2-mode)

commit 2621fccb238fbfcc337cb853c2fba6a57c42d300
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 05:46:21 2013 +0400

    Google Gears has been dead for a while now

diff --git a/js2-mode.el b/js2-mode.el
index eb16a41..afc471e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -180,14 +180,6 @@ variable `js2-include-browser-externs'.")
   "Mozilla Rhino externs.
 Set `js2-include-rhino-externs' to t to include them.")
 
-(defvar js2-gears-externs
-  (mapcar 'symbol-name
-          '(
-            ;; TODO(stevey):  add these
-            ))
-  "Google Gears externs.
-Set `js2-include-gears-externs' to t to include them.")
-
 ;;; Variables
 
 (defun js2-mark-safe-local (name pred)
@@ -822,12 +814,6 @@ See `js2-additional-externs' for more information about 
externs."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-include-gears-externs t
-  "Non-nil to include Google Gears externs in the master externs list.
-See `js2-additional-externs' for more information about externs."
-  :type 'boolean
-  :group 'js2-mode)
-
 (js2-deflocal js2-additional-externs nil
   "A buffer-local list of additional external declarations.
 It is used to decide whether variables are considered undeclared
@@ -10161,7 +10147,6 @@ highlighting features of `js2-mode'."
   (setq js2-default-externs
         (append js2-ecma-262-externs
                 (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-gears-externs js2-gears-externs)
                 (if js2-include-rhino-externs js2-rhino-externs)))
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
@@ -10346,7 +10331,6 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
   (setq js2-default-externs
         (append js2-ecma-262-externs
                 (if js2-include-browser-externs js2-browser-externs)
-                (if js2-include-gears-externs js2-gears-externs)
                 (if js2-include-rhino-externs js2-rhino-externs)))
 
   (setq font-lock-defaults '(nil t))

commit e861ebcbf4bfc303be5ff3866b77e791e14a08fd
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 19 05:44:48 2013 +0400

    Add URL header and some explanation

diff --git a/js2-mode.el b/js2-mode.el
index 59dec5a..eb16a41 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -5,6 +5,8 @@
 ;; Author: Steve Yegge <address@hidden>
 ;;         mooz <address@hidden>
 ;;         Dmitry Gutov <address@hidden>
+;; URL:  https://github.com/mooz/js2-mode/
+;;       http://code.google.com/p/js2-mode/
 ;; Version: 20130217
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
@@ -73,6 +75,10 @@
 ;; This means that `js2-mode' is currently only useful for editing JavaScript
 ;; files, and not for editing JavaScript within <script> tags or templates.
 
+;; The project page on GitHub is used for development and issue tracking.
+;; The original homepage at Google Code is mentioned here for posterity, it has
+;; outdated information and is mostly unmaintained.
+
 ;;; Code:
 
 (eval-when-compile

commit c7999fae536e0cb3af675e1ba308e4ad13497c01
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 08:21:45 2013 +0400

    Remove leftover make-obsolete-variable statement

diff --git a/js2-mode.el b/js2-mode.el
index 1543943..59dec5a 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -219,8 +219,6 @@ Similar to `c-basic-offset'."
   :type 'integer)
 (js2-mark-safe-local 'js2-basic-offset 'integerp)
 
-(make-obsolete-variable 'js2-auto-indent-p 'electric-indent-mode "1.0")
-
 (defcustom js2-bounce-indent-p nil
   "Non-nil to have indent-line function choose among alternatives.
 If nil, the indent-line function will indent to a predetermined column

commit 2f274258aeb4a66e16d3f90bec40b00b6f080dff
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 08:18:50 2013 +0400

    Update copyright notice; switch back to date-based versioning
    
    The latter, by popular demand. Apparently, 2009xxxx > 1.1, so this change 
will
    make the users of the old js2-mode who installed it through package.el (and 
who
    don't use Melpa) definitely notice the new version.

diff --git a/js2-mode.el b/js2-mode.el
index cf0402c..1543943 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1,11 +1,11 @@
 ;;; js2-mode.el --- Improved JavaScript editing mode
 
-;; Copyright (C) 2009, 2011, 2012  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011-2013  Free Software Foundation, Inc.
 
 ;; Author: Steve Yegge <address@hidden>
 ;;         mooz <address@hidden>
 ;;         Dmitry Gutov <address@hidden>
-;; Version: 1.1
+;; Version: 20130217
 ;; Keywords: languages, javascript
 ;; Package-Requires: ((emacs "24.1"))
 

commit cdd25bb4c7723ee0f10c59f0afd8e7a75fd4d031
Merge: ef7de01 807010e
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 08:05:13 2013 +0400

    Merge branch 'emacs24'
    
    Emacs 24-only code is now master, for legacy check out emacs23.
    
    The commit log is going to have a lot of duplicates, sorry about that.
    Still, this way, many users can do a fast-forward merge.

diff --cc js2-mode.el
index d23d8a1,0b5947f..cf0402c
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -209,22 -219,6 +219,7 @@@ Similar to `c-basic-offset'.
    :type 'integer)
  (js2-mark-safe-local 'js2-basic-offset 'integerp)
  
- ;; TODO(stevey):  move this code into a separate minor mode.
- (defcustom js2-mirror-mode nil
-   "Non-nil to insert closing brackets, parens, etc. automatically."
-   :group 'js2-mode
-   :type 'boolean)
- 
- (make-obsolete-variable 'js2-mirror-mode 'electric-pair-mode "1.0")
- 
- (defcustom js2-auto-indent-p nil
-   "Automatic indentation with punctuation characters.
- If non-nil, the current line is indented when certain punctuations
- are inserted."
-   :group 'js2-mode
-   :type 'boolean)
- 
 +(make-obsolete-variable 'js2-auto-indent-p 'electric-indent-mode "1.0")
  
  (defcustom js2-bounce-indent-p nil
    "Non-nil to have indent-line function choose among alternatives.

commit 807010e5ebfe9e3501e679f17cfd5ba3217db870
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:47:08 2013 +0400

    Link to branch emacs23

diff --git a/README.md b/README.md
index bb574f8..ba5bb50 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ additional details.
 Emacs 22 and 23
 ===============
 
-This version requires Emacs 24. For backwards-compatible version, check out 
the [`master` branch](https://github.com/mooz/js2-mode/tree/master).
+This version requires Emacs 24. For a backward compatible version, check out 
the branch [emacs23](https://github.com/mooz/js2-mode/tree/emacs23).
 
 Bugs
 ====

commit c3b45e3d3375f8ecd7f30060432a0265ab93d2db
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:41:17 2013 +0400

    Remove link to js2-highlight-vars-mode, add one to skewer-mode

diff --git a/README.md b/README.md
index 833c798..bb574f8 100644
--- a/README.md
+++ b/README.md
@@ -38,5 +38,5 @@ See Also
 
 Some third-party modes that use the generated syntax tree:
 
-* 
[js2-highlight-vars-mode](http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode)
 * [js2-refactor](https://github.com/magnars/js2-refactor.el)
+* [skewer-mode](https://github.com/skeeto/skewer-mode)

commit ef7de01af0262c366b3e7fffb615bbddd43a1e88
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:41:17 2013 +0400

    Remove link to js2-highlight-vars-mode, add one to skewer-mode

diff --git a/README.md b/README.md
index eba462c..4867219 100644
--- a/README.md
+++ b/README.md
@@ -37,5 +37,5 @@ See Also
 
 Some third-party modes that use the generated syntax tree:
 
-* 
[js2-highlight-vars-mode](http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode)
 * [js2-refactor](https://github.com/magnars/js2-refactor.el)
+* [skewer-mode](https://github.com/skeeto/skewer-mode)

commit 65854534288acb77e47bc45ed407a8e282332438
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:28:03 2013 +0400

    Change the wiki link

diff --git a/README.md b/README.md
index 82c9b52..eba462c 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,7 @@ Description
 
 An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
 
-For some of the user-visible changes, see
-[Changes from the original 
mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
+For some of the latest changes, see [latest user-visible 
changes](https://github.com/mooz/js2-mode/wiki/Latest-user-visible-changes).
 
 Installation
 ======

commit eca4241cb8f0f972b12ec0eda1537605dc28458a
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:28:03 2013 +0400

    Change the wiki link

diff --git a/README.md b/README.md
index a8f5ac8..833c798 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,7 @@ Description
 
 An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
 
-For some of the user-visible changes, see
-[Changes from the original 
mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
+For some of the latest changes, see [latest user-visible 
changes](https://github.com/mooz/js2-mode/wiki/Latest-user-visible-changes).
 
 Installation
 ======

commit 624f5e661849ac91d53afbb333403114eee4ecfb
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:14:38 2013 +0400

    keywords-as-property-names is also valid JS 5.1
    
    Refs #41

diff --git a/js2-mode.el b/js2-mode.el
index b1e0e21..0b5947f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -360,7 +360,7 @@ Examples:
   var foo = {int: 5, while: 6, continue: 7};
   foo.return = 8;
 
-Ecma-262 forbids this syntax, but many browsers support it."
+Ecma-262 5.1 allows this syntax, but some engines still don't."
   :type 'boolean
   :group 'js2-mode)
 

commit bfb482fd6b4ad4c14ddfd23546f44df628b0c1a7
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 07:14:38 2013 +0400

    keywords-as-property-names is also valid JS 5.1
    
    Refs #41

diff --git a/js2-mode.el b/js2-mode.el
index e56f3cd..d23d8a1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -405,7 +405,7 @@ Examples:
   var foo = {int: 5, while: 6, continue: 7};
   foo.return = 8;
 
-Ecma-262 forbids this syntax, but many browsers support it."
+Ecma-262 5.1 allows this syntax, but some engines still don't."
   :type 'boolean
   :group 'js2-mode)
 

commit 6d7b67ece15c78c43ff5ef1cca556def20356bb1
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 06:52:05 2013 +0400

    Trailing comma is legal ecma-262-5.1
    
    Fixes #85

diff --git a/js2-mode.el b/js2-mode.el
index de465f1..e56f3cd 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -337,8 +337,7 @@ even if this flag is non-nil."
 
 (defcustom js2-strict-trailing-comma-warning t
   "Non-nil to warn about trailing commas in array literals.
-Ecma-262 forbids them, but many browsers permit them.  IE is the
-big exception, and can produce bugs if you have trailing commas."
+Ecma-262-5.1 allows them, but older versions of IE raise an error."
   :type 'boolean
   :group 'js2-mode)
 
@@ -1748,7 +1747,7 @@ the correct number of ARGS must be provided."
          "Code has no side effects")
 
 (js2-msg "msg.extra.trailing.comma"
-         "Trailing comma is not legal in an ECMA-262 object initializer")
+         "Trailing comma is not supported in some browsers")
 
 (js2-msg "msg.array.trailing.comma"
          "Trailing comma yields different behavior across browsers")

commit fc2fa199996b6253bf510308569c7afe8b009d2b
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 17 06:52:05 2013 +0400

    Trailing comma is legal ecma-262-5.1
    
    Fixes #85

diff --git a/js2-mode.el b/js2-mode.el
index 69eac43..b1e0e21 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -292,8 +292,7 @@ even if this flag is non-nil."
 
 (defcustom js2-strict-trailing-comma-warning t
   "Non-nil to warn about trailing commas in array literals.
-Ecma-262 forbids them, but many browsers permit them.  IE is the
-big exception, and can produce bugs if you have trailing commas."
+Ecma-262-5.1 allows them, but older versions of IE raise an error."
   :type 'boolean
   :group 'js2-mode)
 
@@ -1664,7 +1663,7 @@ the correct number of ARGS must be provided."
          "Code has no side effects")
 
 (js2-msg "msg.extra.trailing.comma"
-         "Trailing comma is not legal in an ECMA-262 object initializer")
+         "Trailing comma is not supported in some browsers")
 
 (js2-msg "msg.array.trailing.comma"
          "Trailing comma yields different behavior across browsers")

commit 214e28d45b679b6538f8206d6af7be6935dd3038
Author: Leo Liu <address@hidden>
Date:   Thu Feb 14 15:34:19 2013 +0800

    Use setq-local

diff --git a/ack.el b/ack.el
index 8f89873..08e077a 100644
--- a/ack.el
+++ b/ack.el
@@ -32,6 +32,11 @@
 (require 'ansi-color)
 (autoload 'shell-completion-vars "shell")
 
+(eval-when-compile
+  (unless (fboundp 'setq-local)
+    (defmacro setq-local (var val)
+      (list 'set (list 'make-local-variable (list 'quote var)) val))))
+
 (defgroup ack nil
   "Run `ack' and display the results."
   :group 'tools
@@ -196,23 +201,21 @@ This gets tacked on the end of the generated 
expressions.")
   (when (string-match-p "^[ \t]*hg[ \t]" (car compilation-arguments))
     (setq compilation-error-regexp-alist
           '(("^\\(.+?:[0-9]+:\\)\\(?:\\([0-9]+\\):\\)?" 1 2)))
-    (make-local-variable 'compilation-parse-errors-filename-function)
-    (setq compilation-parse-errors-filename-function
-          (lambda (file)
-            (save-match-data
-              (if (string-match "\\(.+\\):\\([0-9]+\\):" file)
-                  (match-string 1 file)
-                file)))))
+    (setq-local compilation-parse-errors-filename-function
+                (lambda (file)
+                  (save-match-data
+                    (if (string-match "\\(.+\\):\\([0-9]+\\):" file)
+                        (match-string 1 file)
+                      file)))))
   ;; Handle `bzr grep' output
   (when (string-match-p "^[ \t]*bzr[ \t]" (car compilation-arguments))
-    (make-local-variable 'compilation-parse-errors-filename-function)
-    (setq compilation-parse-errors-filename-function
-          (lambda (file)
-            (save-match-data
-              ;; 'bzr grep -r' has files like `termcolor.py~147'
-              (if (string-match "\\(.+\\)~\\([0-9]+\\)" file)
-                  (match-string 1 file)
-                file))))))
+    (setq-local compilation-parse-errors-filename-function
+                (lambda (file)
+                  (save-match-data
+                    ;; 'bzr grep -r' has files like `termcolor.py~147'
+                    (if (string-match "\\(.+\\)~\\([0-9]+\\)" file)
+                        (match-string 1 file)
+                      file))))))
 
 (defun ack-mode-display-match ()
   "Display in another window the match in current line."
@@ -222,9 +225,8 @@ This gets tacked on the end of the generated expressions.")
 
 (define-compilation-mode ack-mode "Ack"
   "A compilation mode tailored for ack."
-  (set (make-local-variable 'compilation-disable-input) t)
-  (set (make-local-variable 'compilation-error-face)
-       'compilation-info)
+  (setq-local compilation-disable-input t)
+  (setq-local compilation-error-face 'compilation-info)
   (add-hook 'compilation-filter-hook 'ack-filter nil t)
   (define-key ack-mode-map "\C-o" #'ack-mode-display-match))
 

commit f66b9811b330f1748cb0093270345291f88419a8
Author: Leo Liu <address@hidden>
Date:   Wed Feb 13 16:02:44 2013 +0800

    Enhance minibuffer prompt update feature
    
    New user variable ack-minibuffer-setup-hook.

diff --git a/ack.el b/ack.el
index 586eabd..8f89873 100644
--- a/ack.el
+++ b/ack.el
@@ -89,6 +89,11 @@ Used by `ack-guess-project-root'."
   :type '(repeat string)
   :group 'ack)
 
+(defcustom ack-minibuffer-setup-hook nil
+  "Ack-specific hook for `minibuffer-setup-hook'."
+  :type 'hook
+  :group 'ack)
+
 ;;; ======== END of USER OPTIONS ========
 
 (defvar ack-history nil "History list for ack.")
@@ -223,13 +228,6 @@ This gets tacked on the end of the generated expressions.")
   (add-hook 'compilation-filter-hook 'ack-filter nil t)
   (define-key ack-mode-map "\C-o" #'ack-mode-display-match))
 
-(defun ack-update-minibuffer-prompt (prompt)
-  "Visually replace minibuffer prompt with PROMPT."
-  (when (minibufferp)
-    (let ((inhibit-read-only t))
-      (put-text-property
-       (point-min) (minibuffer-prompt-end) 'display prompt))))
-
 (defun ack-skel-file ()
   "Insert a template for case-insensitive file name search."
   (interactive)
@@ -252,9 +250,6 @@ This gets tacked on the end of the generated expressions.")
          (cmd (or (cdr (assoc which ack-vc-grep-commands))
                   (error "No command provided for `%s grep'" backend))))
     (setq project-root root)
-    (ack-update-minibuffer-prompt
-     (format "Run %s grep in `%s': " backend
-             (file-name-nondirectory (directory-file-name project-root))))
     (delete-minibuffer-contents)
     (skeleton-insert `(nil ,cmd " '" _ "'"))))
 
@@ -302,6 +297,27 @@ Otherwise, interactively choose a directory."
         (ack-default-directory '(16))))
    (t (read-directory-name "In directory: " nil nil t))))
 
+(defun ack-update-minibuffer-prompt (&optional _beg _end _len)
+  (when (minibufferp)
+    (let ((inhibit-read-only t))
+      (save-excursion
+        (goto-char (minibuffer-prompt-end))
+        (when (looking-at "\\(\\w+\\)\\s-")
+          (put-text-property
+           (point-min) (minibuffer-prompt-end)
+           'display
+           (format "Run %s in `%s': "
+                   (match-string-no-properties 1)
+                   (file-name-nondirectory
+                    (directory-file-name project-root)))))))))
+
+(defun ack-minibuffer-setup-function ()
+  (shell-completion-vars)
+  (add-hook 'after-change-functions
+            #'ack-update-minibuffer-prompt nil t)
+  (ack-update-minibuffer-prompt)
+  (run-hooks 'ack-minibuffer-setup-hook))
+
 ;;;###autoload
 (defun ack (command-args &optional directory)
   "Run ack using COMMAND-ARGS and collect output in a buffer.
@@ -318,12 +334,11 @@ minibuffer:
                            default-directory))
          ;; Disable completion cycling; see http://debbugs.gnu.org/12221
          (completion-cycle-threshold nil))
-     (list (minibuffer-with-setup-hook 'shell-completion-vars
-             (read-from-minibuffer
-              (format "Run ack in `%s': "
-                      (file-name-nondirectory
-                       (directory-file-name project-root)))
-              ack-command ack-minibuffer-local-map nil 'ack-history))
+     (list (minibuffer-with-setup-hook 'ack-minibuffer-setup-function
+             (read-from-minibuffer "Ack: "
+                                   ack-command
+                                   ack-minibuffer-local-map
+                                   nil 'ack-history))
            project-root)))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))

commit cd4a73fa21cfc6764a21cad41647a93954d940a4
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 10 10:02:06 2013 +0400

    Mark the obsolete variables as such
    
    Close #80

diff --git a/js2-mode.el b/js2-mode.el
index 2074173..de465f1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -215,6 +215,8 @@ Similar to `c-basic-offset'."
   :group 'js2-mode
   :type 'boolean)
 
+(make-obsolete-variable 'js2-mirror-mode 'electric-pair-mode "1.0")
+
 (defcustom js2-auto-indent-p nil
   "Automatic indentation with punctuation characters.
 If non-nil, the current line is indented when certain punctuations
@@ -222,6 +224,8 @@ are inserted."
   :group 'js2-mode
   :type 'boolean)
 
+(make-obsolete-variable 'js2-auto-indent-p 'electric-indent-mode "1.0")
+
 (defcustom js2-bounce-indent-p nil
   "Non-nil to have indent-line function choose among alternatives.
 If nil, the indent-line function will indent to a predetermined column
@@ -259,24 +263,32 @@ This is unusual for Emacs modes but common in IDEs like 
Eclipse."
   :type 'boolean
   :group 'js2-mode)
 
+(make-obsolete-variable 'js2-indent-on-enter-key nil "1.0")
+
 (defcustom js2-enter-indents-newline nil
   "Non-nil to have Enter/Return key indent the newly-inserted line.
 This is unusual for Emacs modes but common in IDEs like Eclipse."
   :type 'boolean
   :group 'js2-mode)
 
+(make-obsolete-variable 'js2-enter-indents-newline nil "1.0")
+
 (defcustom js2-rebind-eol-bol-keys t
   "Non-nil to rebind `beginning-of-line' and `end-of-line' keys.
 If non-nil, bounce between bol/eol and first/last non-whitespace char."
   :group 'js2-mode
   :type 'boolean)
 
+(make-obsolete-variable 'js2-rebind-eol-bol-keys nil "1.0")
+
 (defcustom js2-electric-keys '("{" "}" "(" ")" "[" "]" ":" ";" "," "*")
   "Keys that auto-indent when `js2-auto-indent-p' is non-nil.
 Each value in the list is passed to `define-key'."
   :type 'list
   :group 'js2-mode)
 
+(make-obsolete-variable 'js2-electric-keys 'electric-indent-chars "1.0")
+
 (defcustom js2-idle-timer-delay 0.2
   "Delay in secs before re-parsing after user makes changes.
 Multiplied by `js2-dynamic-idle-timer-adjust', which see."
@@ -302,6 +314,8 @@ If `js2-dynamic-idle-timer-adjust' is 0 or negative,
   :type 'boolean
   :group 'js2-mode)
 
+(make-obsolete-variable 'js2-mode-escape-quotes nil "1.0")
+
 (defcustom js2-concat-multiline-strings t
   "Non-nil to automatically turn a newline in mid-string into a
 string concatenation.  When `eol', the '+' will be inserted at the
@@ -407,6 +421,8 @@ This is useful for xulrunner apps."
   :type 'boolean
   :group 'js2-mode)
 
+(make-obsolete-variable 'js2-cleanup-whitespace 'before-save-hook "1.0")
+
 (defcustom js2-move-point-on-right-click t
   "Non-nil to move insertion point when you right-click.
 This makes right-click context menu behavior a bit more intuitive,

commit d6d936c7a272ebce700be845d7e54e7d917afdec
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 10 09:03:53 2013 +0400

    Make sure js2-mode-ast is available for callbacks

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index f9215a4..3061905 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -104,8 +104,6 @@ prefix any functions defined inside the IIFE with the 
module name."
   (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))
 
-(declare (special root))
-
 (defun js2-imenu-record-declarations ()
   (let* ((styles (loop for style in js2-imenu-extension-styles
                        when (memq (plist-get style :framework)
@@ -113,9 +111,7 @@ prefix any functions defined inside the IIFE with the 
module name."
                        collect style))
          (re (mapconcat (lambda (style)
                           (concat "\\(" (plist-get style :call-re) "\\)"))
-                        styles "\\|"))
-         ;; Dynamic scoping. Ew.
-         (js2-mode-ast root))
+                        styles "\\|")))
     (goto-char (point-min))
     (while (js2-re-search-forward re nil t)
       (loop for i from 0 to (1- (length styles))
@@ -163,7 +159,7 @@ prefix any functions defined inside the IIFE with the 
module name."
 
 (defun js2-imenu-walk-ast ()
   (js2-visit-ast
-   root
+   js2-mode-ast
    (lambda (node end-p)
      (unless end-p
        (cond
diff --git a/js2-mode.el b/js2-mode.el
index 5502730..2074173 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -879,7 +879,7 @@ externs appropriate for the specific file, perhaps based on 
its path.
 These should go in `js2-additional-externs', which is buffer-local.
 
 Finally, you can add a function to `js2-post-parse-callbacks',
-which is called after parsing completes, and `root' is bound to
+which is called after parsing completes, and `js2-mode-ast' is bound to
 the root of the parse tree.  At this stage you can set up an AST
 node visitor using `js2-visit-ast' and examine the parse tree
 for specific import patterns that may imply the existence of
@@ -7384,6 +7384,7 @@ Scanner should be initialized."
         (push comment (js2-ast-root-comments root))
         (js2-node-add-children root comment)))
     (setf (js2-node-len root) (- end pos))
+    (setq js2-mode-ast root)  ; Make sure this is available for callbacks.
     ;; Give extensions a chance to muck with things before highlighting starts.
     (let ((js2-additional-externs js2-additional-externs))
       (dolist (callback js2-post-parse-callbacks)
@@ -10608,7 +10609,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                     (js2-time
                      (setq interrupted-p
                            (catch 'interrupted
-                             (setq js2-mode-ast (js2-parse))
+                             (js2-parse)
                              ;; if parsing is interrupted, comments and regex
                              ;; literals stay ignored by `parse-partial-sexp'
                              (remove-text-properties (point-min) (point-max)

commit 91a2895d72470c81e67bf40227bbcaa615d8894c
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 10 09:03:53 2013 +0400

    Make sure js2-mode-ast is available for callbacks

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index f9215a4..3061905 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -104,8 +104,6 @@ prefix any functions defined inside the IIFE with the 
module name."
   (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))
 
-(declare (special root))
-
 (defun js2-imenu-record-declarations ()
   (let* ((styles (loop for style in js2-imenu-extension-styles
                        when (memq (plist-get style :framework)
@@ -113,9 +111,7 @@ prefix any functions defined inside the IIFE with the 
module name."
                        collect style))
          (re (mapconcat (lambda (style)
                           (concat "\\(" (plist-get style :call-re) "\\)"))
-                        styles "\\|"))
-         ;; Dynamic scoping. Ew.
-         (js2-mode-ast root))
+                        styles "\\|")))
     (goto-char (point-min))
     (while (js2-re-search-forward re nil t)
       (loop for i from 0 to (1- (length styles))
@@ -163,7 +159,7 @@ prefix any functions defined inside the IIFE with the 
module name."
 
 (defun js2-imenu-walk-ast ()
   (js2-visit-ast
-   root
+   js2-mode-ast
    (lambda (node end-p)
      (unless end-p
        (cond
diff --git a/js2-mode.el b/js2-mode.el
index 702b32c..69eac43 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -843,7 +843,7 @@ externs appropriate for the specific file, perhaps based on 
its path.
 These should go in `js2-additional-externs', which is buffer-local.
 
 Finally, you can add a function to `js2-post-parse-callbacks',
-which is called after parsing completes, and `root' is bound to
+which is called after parsing completes, and `js2-mode-ast' is bound to
 the root of the parse tree.  At this stage you can set up an AST
 node visitor using `js2-visit-ast' and examine the parse tree
 for specific import patterns that may imply the existence of
@@ -7187,6 +7187,7 @@ Scanner should be initialized."
         (push comment (js2-ast-root-comments root))
         (js2-node-add-children root comment)))
     (setf (js2-node-len root) (- end pos))
+    (setq js2-mode-ast root)  ; Make sure this is available for callbacks.
     ;; Give extensions a chance to muck with things before highlighting starts.
     (let ((js2-additional-externs js2-additional-externs))
       (save-excursion
@@ -10448,7 +10449,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                     (js2-time
                      (setq interrupted-p
                            (catch 'interrupted
-                             (setq js2-mode-ast (js2-parse))
+                             (js2-parse)
                              ;; if parsing is interrupted, comments and regex
                              ;; literals stay ignored by `parse-partial-sexp'
                              (remove-text-properties (point-min) (point-max)

commit 2273af9f6bc85e7244f5229d9a53ae5a1d197eb0
Author: Leo Liu <address@hidden>
Date:   Thu Feb 7 22:50:42 2013 +0800

    Bump version number to 0.9

diff --git a/README.rst b/README.rst
index cc3ec52..df1e75a 100644
--- a/README.rst
+++ b/README.rst
@@ -12,7 +12,7 @@ From http://betterthangrep.com/
 
 This package is part of `GNU ELPA <http://elpa.gnu.org>`_.
 
-Feature requests and bug reports are welcome. Thanks.
+Patches, feature requests and bug reports are welcome. Thanks.
 
 Features
 --------
diff --git a/ack.el b/ack.el
index 2c7493e..586eabd 100644
--- a/ack.el
+++ b/ack.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.8
+;; Version: 0.9
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
 ;; URL: https://github.com/leoliu/ack-el

commit 5f9278407351f5b8143b9f989e152723d1fbcc40
Author: Leo Liu <address@hidden>
Date:   Thu Feb 7 16:24:01 2013 +0800

    Fix thinko

diff --git a/ack.el b/ack.el
index 2033c95..2c7493e 100644
--- a/ack.el
+++ b/ack.el
@@ -179,8 +179,8 @@ This gets tacked on the end of the generated expressions.")
      nil nil (4 compilation-column-face nil t))
     ;; none grouping line (--nogroup or --noheading)
     
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     (1 3 (ack--column-start . ack--column-end)
-        nil nil (4 compilation-column-face nil t)))
+     1 3 (ack--column-start . ack--column-end)
+     nil nil (4 compilation-column-face nil t))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit a13e76c84739db1849169efbaf6112626ce720f5
Author: Leo Liu <address@hidden>
Date:   Thu Feb 7 14:53:46 2013 +0800

    New command C-o (ack-mode-display-match) for ack-mode

diff --git a/ack.el b/ack.el
index 22511e9..2033c95 100644
--- a/ack.el
+++ b/ack.el
@@ -209,12 +209,19 @@ This gets tacked on the end of the generated 
expressions.")
                   (match-string 1 file)
                 file))))))
 
+(defun ack-mode-display-match ()
+  "Display in another window the match in current line."
+  (interactive)
+  (setq compilation-current-error (point))
+  (next-error-no-select 0))
+
 (define-compilation-mode ack-mode "Ack"
   "A compilation mode tailored for ack."
   (set (make-local-variable 'compilation-disable-input) t)
   (set (make-local-variable 'compilation-error-face)
        'compilation-info)
-  (add-hook 'compilation-filter-hook 'ack-filter nil t))
+  (add-hook 'compilation-filter-hook 'ack-filter nil t)
+  (define-key ack-mode-map "\C-o" #'ack-mode-display-match))
 
 (defun ack-update-minibuffer-prompt (prompt)
   "Visually replace minibuffer prompt with PROMPT."

commit d74c943aad4b5957ba22fa22ecc026a36c5c1237
Author: Leo Liu <address@hidden>
Date:   Thu Feb 7 14:21:47 2013 +0800

    Remove emacs 23 support in 'master' branch

diff --git a/README.rst b/README.rst
index f0c656a..cc3ec52 100644
--- a/README.rst
+++ b/README.rst
@@ -21,7 +21,6 @@ Features
 - Handle colors using the standard library ``ansi-color.el``
 - Completion for ack options while reading from the minibuffer
 - Support ``git grep``, ``hg grep`` and ``bzr grep``
-- Support both emacs 23 and 24
 
 Screenshots
 -----------
@@ -85,6 +84,12 @@ key bindings may be useful:
   the minibuffer
 - ``TAB`` => completion for ack options
 
+Emacs23
+-------
+
+Check out the `emacs23
+<https://github.com/leoliu/ack-el/tree/emacs23>`_ branch.
+
 Bugs
 ----
 
diff --git a/ack.el b/ack.el
index 6b1655d..22511e9 100644
--- a/ack.el
+++ b/ack.el
@@ -1,4 +1,4 @@
-;;; ack.el --- Emacs interface to ack
+;;; ack.el --- Emacs interface to ack           -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
 
@@ -30,8 +30,7 @@
 
 (require 'compile)
 (require 'ansi-color)
-(when (>= emacs-major-version 24)
-  (autoload 'shell-completion-vars "shell"))
+(autoload 'shell-completion-vars "shell")
 
 (defgroup ack nil
   "Run `ack' and display the results."
@@ -129,10 +128,6 @@ This function is called from `compilation-filter-hook'."
   "Additional things to highlight in ack output.
 This gets tacked on the end of the generated expressions.")
 
-(when (< emacs-major-version 24)
-  (defvar ack--column-start 'ack--column-start)
-  (defvar ack--column-end 'ack--column-end))
-
 (defun ack--column-start ()
   (or (let* ((beg (match-end 0))
              (end (save-excursion
@@ -171,48 +166,11 @@ This gets tacked on the end of the generated 
expressions.")
                        (min (1+ (line-end-position)) (point-max)) 'ack-file 
file)
     (list file)))
 
-;;; For emacs < 24
-(when (< emacs-major-version 24)
-  (defun ack--line (file col)
-    (if (string-match-p "\\`[1-9][0-9]*\\'" (car file))
-        (let ((has-ansi-color (overlays-at (match-beginning 1))))
-          ;; See `compilation-mode-font-lock-keywords' where there is
-          ;; overriding font-locking of FILE. Thus use the display
-          ;; property here to avoid being overridden.
-          (put-text-property
-           (match-beginning 1) (match-end 1)
-           'display
-           (propertize (match-string-no-properties 1)
-                       'face (list (and (not has-ansi-color)
-                                        compilation-line-face)
-                                   :weight 'normal :inherit 'underline)))
-          (list nil (ack--file)
-                (string-to-number (match-string 1))
-                (1- (string-to-number (match-string 3)))))
-      (put-text-property (match-beginning 3)
-                         (match-end 3)
-                         'font-lock-face compilation-line-face)
-      (list nil file
-            (string-to-number (match-string 3))
-            (when (match-string 4)
-              (put-text-property (match-beginning 4)
-                                 (match-end 4)
-                                 'font-lock-face compilation-column-face)
-              (1- (string-to-number (match-string 4))))))))
-
-;;; In emacs-24 and above, `compilation-mode-font-lock-keywords' ->
+;;; `compilation-mode-font-lock-keywords' ->
 ;;; `compilation--ensure-parse' -> `compilation--parse-region' ->
 ;;; `compilation-parse-errors' -> `compilation-error-properties'.
 ;;; `compilation-error-properties' returns nil if a previous pattern
 ;;; in the regexp alist has already been applied in a region.
-;;;
-;;; In emacs-23, `ack-regexp-alist' is a part of `font-lock-keywords'
-;;; after some transformation, so later entries can override earlier
-;;; entries.
-;;;
-;;; The output of 'ack --group --column WHATEVER' matches both regexps
-;;; in `ack-regexp-alist' and this fails emacs-23 in finding the right
-;;; file. So ack--line is used to disambiguate this case.
 
 (defconst ack-error-regexp-alist
   `(;; grouping line (--group or --heading)
@@ -221,15 +179,11 @@ This gets tacked on the end of the generated 
expressions.")
      nil nil (4 compilation-column-face nil t))
     ;; none grouping line (--nogroup or --noheading)
     
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     ,@(if (>= emacs-major-version 24)
-           '(1 3 (ack--column-start . ack--column-end)
-               nil nil (4 compilation-column-face nil t))
-         '(1 ack--line 4)))
+     (1 3 (ack--column-start . ack--column-end)
+        nil nil (4 compilation-column-face nil t)))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 
-(defvar ack--ansi-color-last-marker)
-
 (defvar ack-process-setup-function 'ack-process-setup)
 
 (defun ack-process-setup ()
@@ -237,8 +191,6 @@ This gets tacked on the end of the generated expressions.")
   (when (string-match-p "^[ \t]*hg[ \t]" (car compilation-arguments))
     (setq compilation-error-regexp-alist
           '(("^\\(.+?:[0-9]+:\\)\\(?:\\([0-9]+\\):\\)?" 1 2)))
-    (when (< emacs-major-version 24)
-      (setq font-lock-keywords (compilation-mode-font-lock-keywords)))
     (make-local-variable 'compilation-parse-errors-filename-function)
     (setq compilation-parse-errors-filename-function
           (lambda (file)
@@ -262,16 +214,7 @@ This gets tacked on the end of the generated expressions.")
   (set (make-local-variable 'compilation-disable-input) t)
   (set (make-local-variable 'compilation-error-face)
        'compilation-info)
-  (if (>= emacs-major-version 24)
-      (add-hook 'compilation-filter-hook 'ack-filter nil t)
-    (set (make-local-variable 'ack--ansi-color-last-marker)
-         (point-min-marker))
-    (font-lock-add-keywords
-     nil '(((lambda (limit)
-              (let ((beg (marker-position ack--ansi-color-last-marker)))
-                (move-marker ack--ansi-color-last-marker limit)
-                (ansi-color-apply-on-region beg ack--ansi-color-last-marker))
-              nil))))))
+  (add-hook 'compilation-filter-hook 'ack-filter nil t))
 
 (defun ack-update-minibuffer-prompt (prompt)
   "Visually replace minibuffer prompt with PROMPT."
@@ -285,7 +228,7 @@ This gets tacked on the end of the generated expressions.")
   (interactive)
   (delete-minibuffer-contents)
   (let ((ack (or (car (split-string ack-command nil t)) "ack")))
-    (skeleton-insert '(nil ack " -g '(?i:" _ ")'"))))
+    (skeleton-insert `(nil ,ack " -g '(?i:" _ ")'"))))
 
 (defvar project-root)                   ; dynamically bound in `ack'
 
@@ -306,7 +249,7 @@ This gets tacked on the end of the generated expressions.")
      (format "Run %s grep in `%s': " backend
              (file-name-nondirectory (directory-file-name project-root))))
     (delete-minibuffer-contents)
-    (skeleton-insert '(nil cmd " '" _ "'"))))
+    (skeleton-insert `(nil ,cmd " '" _ "'"))))
 
 (defun ack-yank-symbol-at-point ()
   "Yank the symbol from the window before entering the minibuffer."
@@ -321,9 +264,7 @@ This gets tacked on the end of the generated expressions.")
 (defvar ack-minibuffer-local-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
-    (define-key map "\t" (if (>= emacs-major-version 24)
-                             'completion-at-point
-                           'pcomplete))
+    (define-key map "\t" 'completion-at-point)
     (define-key map "\M-I" 'ack-skel-file)
     (define-key map "\M-G" 'ack-skel-vc-grep)
     (define-key map "\M-Y" 'ack-yank-symbol-at-point)
@@ -370,9 +311,7 @@ minibuffer:
                            default-directory))
          ;; Disable completion cycling; see http://debbugs.gnu.org/12221
          (completion-cycle-threshold nil))
-     (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
-                                           'shell-completion-vars
-                                         'pcomplete-shell-setup)
+     (list (minibuffer-with-setup-hook 'shell-completion-vars
              (read-from-minibuffer
               (format "Run ack in `%s': "
                       (file-name-nondirectory
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index 766168a..942a552 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -1,4 +1,4 @@
-;;; pcmpl-ack.el --- completion for ack tool
+;;; pcmpl-ack.el --- completion for ack tool    -*- lexical-binding: t; -*-
 
 ;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
 

commit 0ce35d2e0edb36f9616d15beee26516c373109d7
Author: Leo Liu <address@hidden>
Date:   Tue Feb 5 21:19:28 2013 +0800

    Customise error message with ggtags-global-error

diff --git a/ggtags.el b/ggtags.el
index 75c395a..d5a4037 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
-;; Version: 0.5
+;; Version: 0.6
 ;; Keywords: tools, convenience
 ;; Created: 2013-01-29
 ;; URL: https://github.com/leoliu/ggtags
@@ -69,6 +69,10 @@ If nil, use Emacs default."
 
 (defvar ggtags-current-tag-name nil)
 
+;; Used by ggtags-global-mode
+(defvar ggtags-global-error "match"
+  "Stem of message to print when no matches are found.")
+
 (defmacro ggtags-ignore-file-error (&rest body)
   (declare (indent 0))
   `(condition-case nil
@@ -450,10 +454,6 @@ When called with prefix, ask the name and kind of tag."
     (forward-line (1- line))
     (ggtags-move-to-tag name)))
 
-;; NOTE: `ggtags-build-imenu-index' is signficantly faster and more
-;; precise than the similar feature provided by cc mode. Tested with
-;; ClassFileWriter.java of the rhino project.
-
 ;;;###autoload
 (defun ggtags-build-imenu-index ()
   "A function suitable for `imenu-create-index-function'."

commit 8f1b568741b158db05b9d7f62960a42e902f80a1
Author: Leo Liu <address@hidden>
Date:   Tue Feb 5 09:16:39 2013 +0800

    Better handling of GTAGSLIBPATH in ggtags-tag-names

diff --git a/ggtags.el b/ggtags.el
index 08f36eb..75c395a 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -92,6 +92,9 @@ Return -1 if it does not exist."
         (float-time (nth 5 (file-attributes file)))
       -1)))
 
+(defun ggtags-get-libpath ()
+  (split-string (or (getenv "GTAGSLIBPATH") "") ":" t))
+
 (defun ggtags-cache-get (key)
   (assoc key ggtags-cache))
 
@@ -142,6 +145,19 @@ Return -1 if it does not exist."
                   (error "%s" (comment-string-strip (buffer-string) t t))))))
         (error "Aborted"))))
 
+(defun ggtags-tag-names-1 (root &optional prefix)
+  (when root
+    (if (ggtags-cache-stale-p root)
+        (let* ((default-directory (file-name-as-directory root))
+               (tags (with-demoted-errors
+                       (split-string
+                        (with-output-to-string
+                          (call-process "global" nil (list standard-output nil)
+                                        nil "-c" (or prefix "")))))))
+          (and tags (ggtags-cache-set root tags))
+          tags)
+      (cadr (ggtags-cache-get root)))))
+
 ;;;###autoload
 (defun ggtags-tag-names (&optional prefix)
   "Get a list of tag names starting with PREFIX."
@@ -150,16 +166,9 @@ Return -1 if it does not exist."
       (if (zerop (call-process "global" nil nil nil "-u"))
           (ggtags-cache-mark-dirty root nil)
         (message "ggtags: error running 'global -u'")))
-    (if (ggtags-cache-stale-p root)
-        (let ((tags (ggtags-ignore-file-error
-                      (split-string
-                       (with-output-to-string
-                         (call-process "global" nil (list standard-output nil)
-                                       nil "-cT" (or prefix "")))))))
-          (when tags
-            (ggtags-cache-set root tags))
-          tags)
-      (cadr (ggtags-cache-get root)))))
+    (apply 'append (mapcar (lambda (r)
+                             (ggtags-tag-names-1 r prefix))
+                           (cons root (ggtags-get-libpath))))))
 
 (defun ggtags-read-tag (quick)
   (ggtags-ensure-root-directory)
@@ -356,8 +365,7 @@ When called with prefix, ask the name and kind of tag."
   "Kill all buffers visiting files in the root directory."
   (interactive "p")
   (ggtags-check-root-directory)
-  (let ((gtagslibpath (split-string (or (getenv "GTAGSLIBPATH") "") ":" t))
-        (root (ggtags-root-directory))
+  (let ((root (ggtags-root-directory))
         (count 0)
         (some (lambda (pred list)
                 (loop for x in list when (funcall pred x) return it))))
@@ -367,7 +375,7 @@ When called with prefix, ask the name and kind of tag."
                        (buffer-file-name buf))))
         (when (and file (funcall some (apply-partially #'file-in-directory-p
                                                        (file-truename file))
-                                 (cons root gtagslibpath)))
+                                 (cons root (ggtags-get-libpath))))
           (and (kill-buffer buf)
                (incf count)))))
     (and interactive

commit 291285e9edd45a4e8a04807779b2d8f906c8c4c1
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Feb 4 12:45:59 2013 +0100

    Fix error message in condition-case.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index ebd2a74..b806358 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -151,7 +151,7 @@ See `with-eldoc-in-minibuffer'."
             (when doc (funcall eldoc-in-minibuffer-show-fn doc))))
       (scan-error nil)
       (beginning-of-buffer nil)
-      (error (and debug-on-error (message "Eldoc in minibuffer error: %S" 
err))))))
+      (error (message "Eldoc in minibuffer error: %S" err)))))
 
 (defun eval-expression-with-eldoc ()
   "Eval expression with eldoc support in mode-line."

commit 920957f2004997dbe1f497432f6728c30c3da394
Author: Leo Liu <address@hidden>
Date:   Sat Feb 2 17:54:42 2013 +0800

    Update README.rst

diff --git a/README.rst b/README.rst
index 6418253..efe01d4 100644
--- a/README.rst
+++ b/README.rst
@@ -6,9 +6,10 @@ A package for working with `GNU Global
 <http://www.gnu.org/software/global>`_ source tagging system inside
 Emacs.
 
-This package is part of `GNU ELPA <http://elpa.gnu.org>`_.
+This package is part of `GNU ELPA <http://elpa.gnu.org>`_
+(``M-x list-packages``).
 
-Feature requests and bug reports are welcome. Thanks.
+Patches, feature requests and bug reports are welcome. Thanks.
 
 Features
 ~~~~~~~~
@@ -23,18 +24,38 @@ Screenshot
 ~~~~~~~~~~
 
 .. figure:: http://i.imgur.com/d430rmm.png
-   :width: 400px
+   :width: 500px
    :target: http://i.imgur.com/d430rmm.png
    :alt: ggtags.png
 
-Install
-~~~~~~~
+Tutorial
+~~~~~~~~
+
+Type ``M-x ggtags-mode`` to enable the minor mode, or as usual enable
+it in your desired major mode hooks. When the mode is on the symbol at
+point is underlined if it is a valid tag.
+
+``M-.`` finds definitions or references according to the tag at point,
+i.e. if point is at a definition tag find references and vice versa.
+``C-u M-.`` is verbose and will ask you the name - with completion
+- and the type of tag to search.
+
+If multiple matches are found, navigation mode is entered. In this
+mode, ``M-n`` and ``M-p`` moves to next and previous match, ``M-}``
+and ``M-{`` to next and previous file respectively. ``M-o`` toggles
+between full and abbreviated displays of file names in the auxiliary
+popup window. When you locate the right match, press RET to finish
+which hides the auxiliary window and exits navigation mode. You can
+resume the search using ``M-,``. To abort the search press ``M-*``.
 
-Place ``ggtags.el`` in the ``load-path`` and add to your init file::
+Normally after a few searches a dozen buffers are created visiting
+files tracked by GNU Global. ``C-c M-k`` helps clean them up.
 
-  (require 'ggtags)
+Development
+~~~~~~~~~~~
 
-Use ``M-x ggtags-mode`` to enable the mode and ``M-.`` to find tags.
+The goal is to make working with GNU Global in Emacs as effortless and
+intuitively as possible.
 
 Bugs
 ~~~~

commit 07062a9b12e63b3069d9790149873510e1c64c36
Author: Leo Liu <address@hidden>
Date:   Sat Feb 2 17:36:55 2013 +0800

    Be consistent in popping up windows

diff --git a/ggtags.el b/ggtags.el
index c4a9d1f..08f36eb 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -201,7 +201,9 @@ When called with prefix, ask the name and kind of tag."
   (interactive)
   (ggtags-ensure-global-buffer
     (ggtags-navigation-mode +1)
-    (compile-goto-error)))
+    (let ((split-window-preferred-function
+           (lambda (w) (split-window (frame-root-window w)))))
+      (compile-goto-error))))
 
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
   (let ((count (save-excursion

commit 7e914a0ae0b19531bb7e0040e01943d2f3079fa9
Author: Leo Liu <address@hidden>
Date:   Sat Feb 2 17:28:54 2013 +0800

    Teach ggtags-kill-file-buffers to look in GTAGSLIBPATH

diff --git a/ggtags.el b/ggtags.el
index b22f61c..c4a9d1f 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -354,13 +354,18 @@ When called with prefix, ask the name and kind of tag."
   "Kill all buffers visiting files in the root directory."
   (interactive "p")
   (ggtags-check-root-directory)
-  (let ((root (ggtags-root-directory))
-        (count 0))
+  (let ((gtagslibpath (split-string (or (getenv "GTAGSLIBPATH") "") ":" t))
+        (root (ggtags-root-directory))
+        (count 0)
+        (some (lambda (pred list)
+                (loop for x in list when (funcall pred x) return it))))
     (dolist (buf (buffer-list))
       (let ((file (and (buffer-live-p buf)
                        (not (eq buf (current-buffer)))
                        (buffer-file-name buf))))
-        (when (and file (file-in-directory-p (file-truename file) root))
+        (when (and file (funcall some (apply-partially #'file-in-directory-p
+                                                       (file-truename file))
+                                 (cons root gtagslibpath)))
           (and (kill-buffer buf)
                (incf count)))))
     (and interactive

commit 30a7a207c3f07344e98a9b5adccff89eff11b278
Author: Leo Liu <address@hidden>
Date:   Sat Feb 2 17:11:24 2013 +0800

    Bind M-, to ggtags-find-tag-resume

diff --git a/ggtags.el b/ggtags.el
index 1e0d320..b22f61c 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -408,7 +408,7 @@ When called with prefix, ask the name and kind of tag."
 (defvar ggtags-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map "\M-." 'ggtags-find-tag)
-    (define-key map "\C-c\M-n" 'ggtags-find-tag-resume)
+    (define-key map "\M-," 'ggtags-find-tag-resume)
     (define-key map "\C-c\M-k" 'ggtags-kill-file-buffers)
     map))
 

commit 74eea614e64b29d0b00f0df6c3b1946014ec7d23
Author: Leo Liu <address@hidden>
Date:   Sat Feb 2 01:42:47 2013 +0800

    Command ggtags-find-tag learns to do what I mean
    
    See: http://article.gmane.org/gmane.comp.gnu.global.general/329

diff --git a/ggtags.el b/ggtags.el
index f9bd7c3..1e0d320 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -161,22 +161,23 @@ Return -1 if it does not exist."
           tags)
       (cadr (ggtags-cache-get root)))))
 
-(defun ggtags-read-tag (&optional reference)
+(defun ggtags-read-tag (quick)
   (ggtags-ensure-root-directory)
   (let* ((tags (ggtags-tag-names))
          (sym (thing-at-point 'symbol))
          (default (and (member sym tags) sym)))
     (setq ggtags-current-tag-name
-          (completing-read
-           (format (if default
-                       "%s for tag (default %s): "
-                     "%s for tag: ")
-                   (if reference "Reference" "Definition") default)
-           tags nil t nil nil default))))
+          (if quick (or default (error "No valid tag at point"))
+            (completing-read
+             (format (if default "Tag (default %s): " "Tag: ") default)
+             tags nil t nil nil default)))))
 
 ;;;###autoload
-(defun ggtags-find-tag (name &optional reference)
-  (interactive (list (ggtags-read-tag current-prefix-arg)
+(defun ggtags-find-tag (name &optional verbose)
+  "Find definitions or references to tag NAME by context.
+If point is at a definition tag, find references, and vice versa.
+When called with prefix, ask the name and kind of tag."
+  (interactive (list (ggtags-read-tag (not current-prefix-arg))
                      current-prefix-arg))
   (ggtags-check-root-directory)
   (ggtags-navigation-mode +1)
@@ -184,9 +185,17 @@ Return -1 if it does not exist."
   (let ((split-window-preferred-function
          (lambda (w) (split-window (frame-root-window w))))
         (default-directory (ggtags-root-directory)))
-    (compilation-start (format "global -v%s --result=grep \"%s\""
-                               (if reference "r" "") name)
-                       'ggtags-global-mode)))
+    (compilation-start
+     (if verbose
+         (format "global -v%s --result=grep \"%s\""
+                 (if (y-or-n-p "Kind (y for definition n for reference)? ")
+                     "" "r")
+                 name)
+       (format "global -v --result=grep --from-here=%d:%s \"%s\""
+               (line-number-at-pos)
+               (expand-file-name buffer-file-name)
+               name))
+     'ggtags-global-mode)))
 
 (defun ggtags-find-tag-resume ()
   (interactive)

commit 10801fc4e6f4c42069b0be08f372053a8e5f7c81
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 21:01:10 2013 +0800

    Tweak parameters to global in ggtags-tag-names
    
    -T tells global to include tags from tag files in GTAGSLIBPATH.

diff --git a/ggtags.el b/ggtags.el
index 5653b3c..f9bd7c3 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -155,7 +155,7 @@ Return -1 if it does not exist."
                       (split-string
                        (with-output-to-string
                          (call-process "global" nil (list standard-output nil)
-                                       nil "-c" (or prefix "")))))))
+                                       nil "-cT" (or prefix "")))))))
           (when tags
             (ggtags-cache-set root tags))
           tags)

commit 273978d3395868d4aaef8001cf5f15d17b63feec
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 21:00:58 2013 +0800

    Highlight tag at point using idle timer for efficiency
    
    Also enhance ggtags-highlight-tag-at-point to re-highlight tag at
    point correctly after it is modified.

diff --git a/ggtags.el b/ggtags.el
index 7929e6e..5653b3c 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -194,28 +194,6 @@ Return -1 if it does not exist."
     (ggtags-navigation-mode +1)
     (compile-goto-error)))
 
-(defvar ggtags-tag-overlay nil)
-(make-variable-buffer-local 'ggtags-tag-overlay)
-
-(defun ggtags-highlight-tag-at-point ()
-  (unless (overlayp ggtags-tag-overlay)
-    (setq ggtags-tag-overlay (make-overlay (point) (point)))
-    (overlay-put ggtags-tag-overlay 'ggtags t))
-  (let ((bounds (bounds-of-thing-at-point 'symbol)))
-    (cond
-     ((not bounds)
-      (overlay-put ggtags-tag-overlay 'face nil)
-      (move-overlay ggtags-tag-overlay (point) (point)))
-     ((notany (lambda (o)
-                (overlay-get o 'ggtags))
-              (overlays-at (car bounds)))
-      (move-overlay ggtags-tag-overlay (car bounds) (cdr bounds))
-      (overlay-put ggtags-tag-overlay 'face
-                   (when (member (buffer-substring (car bounds) (cdr bounds))
-                                 (ggtags-tag-names))
-                     'ggtags-highlight))
-      (overlay-put ggtags-tag-overlay 'window t)))))
-
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
   (let ((count (save-excursion
                  (goto-char (point-max))
@@ -383,6 +361,41 @@ Return -1 if it does not exist."
   (let ((root (ggtags-root-directory)))
     (and root (ggtags-cache-mark-dirty root t))))
 
+(defvar ggtags-tag-overlay nil)
+(defvar ggtags-highlight-tag-timer nil)
+(make-variable-buffer-local 'ggtags-tag-overlay)
+
+(defun ggtags-highlight-tag-at-point (buffer)
+  (when (eq buffer (current-buffer))
+    (unless (overlayp ggtags-tag-overlay)
+      (setq ggtags-tag-overlay (make-overlay (point) (point)))
+      (overlay-put ggtags-tag-overlay 'ggtags t))
+    (let* ((bounds (bounds-of-thing-at-point 'symbol))
+           (valid-tag (when bounds
+                        (member (buffer-substring (car bounds) (cdr bounds))
+                                (ggtags-tag-names))))
+           (o ggtags-tag-overlay)
+           (done-p (lambda ()
+                     (and (memq o (overlays-at (car bounds)))
+                          (= (overlay-start o) (car bounds))
+                          (= (overlay-end o) (cdr bounds))
+                          (or (and valid-tag (overlay-get o 'face))
+                              (and (not valid-tag) (not (overlay-get o 
'face))))))))
+      (cond
+       ((not bounds)
+        (overlay-put ggtags-tag-overlay 'face nil)
+        (move-overlay ggtags-tag-overlay (point) (point)))
+       ((not (funcall done-p))
+        (move-overlay o (car bounds) (cdr bounds))
+        (overlay-put o 'face (and valid-tag 'ggtags-highlight)))))))
+
+(defun ggtags-post-command-function ()
+  (when (timerp ggtags-highlight-tag-timer)
+    (cancel-timer ggtags-highlight-tag-timer))
+  (setq ggtags-highlight-tag-timer
+        (run-with-idle-timer 0.2 nil 'ggtags-highlight-tag-at-point
+                             (current-buffer))))
+
 (defvar ggtags-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map "\M-." 'ggtags-find-tag)
@@ -398,9 +411,9 @@ Return -1 if it does not exist."
         (or (ggtags-root-directory)
             (message "File GTAGS not found"))
         (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
-        (add-hook 'post-command-hook 'ggtags-highlight-tag-at-point nil t))
+        (add-hook 'post-command-hook 'ggtags-post-command-function nil t))
     (remove-hook 'after-save-hook 'ggtags-after-save-function t)
-    (remove-hook 'post-command-hook 'ggtags-highlight-tag-at-point t)
+    (remove-hook 'post-command-hook 'ggtags-post-command-function t)
     (and (overlayp ggtags-tag-overlay)
          (delete-overlay ggtags-tag-overlay))
     (setq ggtags-tag-overlay nil)))

commit 69b1b57fa8a9ecbb80930d028be30aaf0f934050
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 19:05:28 2013 +0800

    Remove use of user-error in ggtags-mode definition
    
    which prevents following forms from execution.

diff --git a/ggtags.el b/ggtags.el
index a6416f2..7929e6e 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -395,9 +395,8 @@ Return -1 if it does not exist."
   :lighter (:eval (if ggtags-navigation-mode "" " GG"))
   (if ggtags-mode
       (progn
-        (unless (ggtags-root-directory)
-          (funcall (if (fboundp 'user-error) 'user-error 'message)
-                   "File GTAGS not found"))
+        (or (ggtags-root-directory)
+            (message "File GTAGS not found"))
         (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
         (add-hook 'post-command-hook 'ggtags-highlight-tag-at-point nil t))
     (remove-hook 'after-save-hook 'ggtags-after-save-function t)

commit c1d27be5a4b47ff5a3b36386531741dd7cf177b9
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 13:24:01 2013 +0800

    Rename ggtags-cache-timestamp to ggtags-get-timestamp

diff --git a/ggtags.el b/ggtags.el
index 54a4255..a6416f2 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -84,8 +84,9 @@ If nil, use Emacs default."
          (error "No global buffer found"))
      (with-current-buffer compilation-last-buffer ,@body)))
 
-(defun ggtags-cache-timestamp (root)
-  "Get the timestamp of file GTAGS in ROOT directory."
+(defun ggtags-get-timestamp (root)
+  "Get the timestamp (float) of file GTAGS in ROOT directory.
+Return -1 if it does not exist."
   (let ((file (expand-file-name "GTAGS" root)))
     (if (file-exists-p file)
         (float-time (nth 5 (file-attributes file)))
@@ -112,7 +113,7 @@ If nil, use Emacs default."
 
 (defun ggtags-cache-stale-p (key)
   "Value is non-nil if tags in cache needs to be rebuilt."
-  (> (ggtags-cache-timestamp key)
+  (> (ggtags-get-timestamp key)
      (or (fourth (ggtags-cache-get key)) 0)))
 
 ;;;###autoload

commit d2b33b2a37726e5ccb36c9eea68ee3446d442bc2
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 01:54:16 2013 +0800

    Do not abuse assert in what it is designed for
    
    An `assert' should be used for something that should *never* be false.

diff --git a/ggtags.el b/ggtags.el
index b3219c2..54a4255 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -78,10 +78,10 @@ If nil, use Emacs default."
 (defmacro ggtags-ensure-global-buffer (&rest body)
   (declare (indent 0))
   `(progn
-     (assert (and (buffer-live-p compilation-last-buffer)
-                  (with-current-buffer compilation-last-buffer
-                    (derived-mode-p 'ggtags-global-mode)))
-             nil "No global buffer found")
+     (or (and (buffer-live-p compilation-last-buffer)
+              (with-current-buffer compilation-last-buffer
+                (derived-mode-p 'ggtags-global-mode)))
+         (error "No global buffer found"))
      (with-current-buffer compilation-last-buffer ,@body)))
 
 (defun ggtags-cache-timestamp (root)
@@ -124,13 +124,13 @@ If nil, use Emacs default."
          (comment-string-strip (buffer-string) t t))))))
 
 (defun ggtags-check-root-directory ()
-  (assert (ggtags-root-directory) nil "File GTAGS not found"))
+  (or (ggtags-root-directory) (error "File GTAGS not found")))
 
 (defun ggtags-ensure-root-directory ()
   (or (ggtags-root-directory)
       (if (yes-or-no-p "File GTAGS not found; run gtags? ")
           (let ((root (read-directory-name "Directory: " nil nil t)))
-            (assert (not (zerop (length root))) nil "No directory chosen")
+            (and (= (length root) 0) (error "No directory chosen"))
             (ggtags-ignore-file-error
               (with-temp-buffer
                 (if (zerop (let ((default-directory

commit 7c55d29882ff67a19368bab5ed8bf93082a8377e
Author: Leo Liu <address@hidden>
Date:   Fri Feb 1 00:56:23 2013 +0800

    Fix ggtags-global-exit-message-function

diff --git a/ggtags.el b/ggtags.el
index 120893b..b3219c2 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -1,6 +1,6 @@
 ;;; ggtags.el --- GNU Global source code tagging system -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2013  Leo Liu
+;; Copyright (C) 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Version: 0.5
@@ -217,9 +217,10 @@ If nil, use Emacs default."
 
 (defun ggtags-global-exit-message-function (_process-status exit-status msg)
   (let ((count (save-excursion
-                 (goto-char (point-min))
-                 (and (re-search-forward "^\\([0-9]+\\) objects? located" nil 
t)
-                      (string-to-number (match-string 1))))))
+                 (goto-char (point-max))
+                 (if (re-search-backward "^\\([0-9]+\\) objects? located" nil 
t)
+                     (string-to-number (match-string 1))
+                   0))))
     (cons (if (> exit-status 0)
               msg
             (format "found %d %s" count (if (= count 1) "match" "matches")))

commit c1d78d95db50af380f53f4b4c0737434e41ebf1b
Author: Leo Liu <address@hidden>
Date:   Thu Jan 31 16:55:04 2013 +0800

    Actually turn off ggtags-navigation-mode when in minibuffer

diff --git a/ggtags.el b/ggtags.el
index 05b8044..120893b 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -353,10 +353,9 @@ If nil, use Emacs default."
   (if ggtags-navigation-mode
       (progn
         (add-hook 'next-error-hook 'ggtags-move-to-tag)
-        (add-hook 'minibuffer-setup-hook
-                  'ggtags-minibuffer-setup-function nil t))
+        (add-hook 'minibuffer-setup-hook 'ggtags-minibuffer-setup-function))
     (remove-hook 'next-error-hook 'ggtags-move-to-tag)
-    (remove-hook 'minibuffer-setup-hook 'ggtags-minibuffer-setup-function t)))
+    (remove-hook 'minibuffer-setup-hook 'ggtags-minibuffer-setup-function)))
 
 (defun ggtags-minibuffer-setup-function ()
   ;; Disable ggtags-navigation-mode in minibuffer.

commit 7450e102b1108ec2edc319a4d61ecc6f633be961
Author: Leo Liu <address@hidden>
Date:   Thu Jan 31 16:53:57 2013 +0800

    Ignore bogus file lines in ggtags-abbreviate-files

diff --git a/ggtags.el b/ggtags.el
index 60bdc2a..05b8044 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -247,9 +247,12 @@ If nil, use Emacs default."
   (goto-char start)
   (when ggtags-global-abbreviate-filename
     (while (re-search-forward "^\\([^:\n]+\\):[0-9]+:" end t)
-      (when (or (not (numberp ggtags-global-abbreviate-filename))
-                (> (length (match-string 1))
-                   ggtags-global-abbreviate-filename))
+      (when (and (or (not (numberp ggtags-global-abbreviate-filename))
+                     (> (length (match-string 1))
+                        ggtags-global-abbreviate-filename))
+                 ;; Ignore bogus file lines such as:
+                 ;;     Global found 2 matches at Thu Jan 31 13:45:19
+                 (get-text-property (match-beginning 0) 'compilation-message))
         (ggtags-abbreviate-file (match-beginning 1) (match-end 1))))))
 
 (defun ggtags-handle-single-match (buf _how)

commit 843a78d2a4fedd18386510ee78152d31898c74ee
Author: Leo Liu <address@hidden>
Date:   Tue Jan 29 11:42:40 2013 +0800

    Initial import

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..02fbd33
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+.PHONY: all clean
+
+ELCFILES = $(addsuffix .elc, $(basename $(wildcard *.el)))
+
+all: $(ELCFILES)
+
+%.elc : %.el
+       @echo Compiling $<
+       @emacs -batch -q -no-site-file -f batch-byte-compile $<
+
+clean:
+       @rm -f *.elc
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..6418253
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,42 @@
+=========================
+ Use GNU Global in Emacs
+=========================
+ 
+A package for working with `GNU Global
+<http://www.gnu.org/software/global>`_ source tagging system inside
+Emacs.
+
+This package is part of `GNU ELPA <http://elpa.gnu.org>`_.
+
+Feature requests and bug reports are welcome. Thanks.
+
+Features
+~~~~~~~~
+
+#. Automatically run ``global -u`` when needed
+#. Highlight valid tag at point
+#. Built on top of ``compile.el`` (asynchonrous and other nice
+   features)
+#. Abbreviated display of file names
+
+Screenshot
+~~~~~~~~~~
+
+.. figure:: http://i.imgur.com/d430rmm.png
+   :width: 400px
+   :target: http://i.imgur.com/d430rmm.png
+   :alt: ggtags.png
+
+Install
+~~~~~~~
+
+Place ``ggtags.el`` in the ``load-path`` and add to your init file::
+
+  (require 'ggtags)
+
+Use ``M-x ggtags-mode`` to enable the mode and ``M-.`` to find tags.
+
+Bugs
+~~~~
+
+https://github.com/leoliu/ggtags/issues
diff --git a/ggtags.el b/ggtags.el
new file mode 100644
index 0000000..60bdc2a
--- /dev/null
+++ b/ggtags.el
@@ -0,0 +1,433 @@
+;;; ggtags.el --- GNU Global source code tagging system -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2013  Leo Liu
+
+;; Author: Leo Liu <address@hidden>
+;; Version: 0.5
+;; Keywords: tools, convenience
+;; Created: 2013-01-29
+;; URL: https://github.com/leoliu/ggtags
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Use GNU Global source code tagging system in Emacs.
+;; http://www.gnu.org/software/global
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'compile)
+(require 'etags)                        ; for find-tag-marker-ring
+
+(if (not (fboundp 'comment-string-strip))
+    (autoload 'comment-string-strip "newcomment"))
+
+(eval-when-compile
+  (unless (fboundp 'setq-local)
+    (defmacro setq-local (var val)
+      (list 'set (list 'make-local-variable (list 'quote var)) val))))
+
+(defgroup ggtags nil
+  "GNU Global source code tagging system."
+  :group 'tools)
+
+(defface ggtags-highlight '((t (:underline t)))
+  "Face used to highlight a valid tag at point.")
+
+(defcustom ggtags-auto-jump-to-first-match t
+  "Non-nil to automatically jump to the first match."
+  :type 'boolean
+  :group 'ggtags)
+
+(defcustom ggtags-global-window-height 8 ; ggtags-global-mode
+  "Number of lines for the 'global' popup window.
+If nil, use Emacs default."
+  :type '(choice (const :tag "Default" nil) integer)
+  :group 'ggtags)
+
+(defcustom ggtags-global-abbreviate-filename 35
+  "Non-nil to display file names abbreviated such as '/u/b/env'."
+  :type '(choice (const :tag "No" nil)
+                 (const :tag "Always" t)
+                 integer)
+  :group 'ggtags)
+
+(defvar ggtags-cache nil)               ; (ROOT TABLE DIRTY TIMESTAMP)
+
+(defvar ggtags-current-tag-name nil)
+
+(defmacro ggtags-ignore-file-error (&rest body)
+  (declare (indent 0))
+  `(condition-case nil
+       (progn ,@body)
+     (file-error nil)))
+
+(defmacro ggtags-ensure-global-buffer (&rest body)
+  (declare (indent 0))
+  `(progn
+     (assert (and (buffer-live-p compilation-last-buffer)
+                  (with-current-buffer compilation-last-buffer
+                    (derived-mode-p 'ggtags-global-mode)))
+             nil "No global buffer found")
+     (with-current-buffer compilation-last-buffer ,@body)))
+
+(defun ggtags-cache-timestamp (root)
+  "Get the timestamp of file GTAGS in ROOT directory."
+  (let ((file (expand-file-name "GTAGS" root)))
+    (if (file-exists-p file)
+        (float-time (nth 5 (file-attributes file)))
+      -1)))
+
+(defun ggtags-cache-get (key)
+  (assoc key ggtags-cache))
+
+(defun ggtags-cache-set (key val &optional dirty)
+  (let ((c (ggtags-cache-get key)))
+    (if c
+        (setcdr c (list val dirty (float-time)))
+      (push (list key val dirty (float-time)) ggtags-cache))))
+
+(defun ggtags-cache-mark-dirty (key flag)
+  "Return non-nil if operation is successful."
+  (let ((cache (ggtags-cache-get key)))
+    (when cache
+      (setcar (cddr cache) flag))))
+
+(defun ggtags-cache-dirty-p (key)
+  "Value is non-nil if 'global -u' is needed."
+  (third (ggtags-cache-get key)))
+
+(defun ggtags-cache-stale-p (key)
+  "Value is non-nil if tags in cache needs to be rebuilt."
+  (> (ggtags-cache-timestamp key)
+     (or (fourth (ggtags-cache-get key)) 0)))
+
+;;;###autoload
+(defun ggtags-root-directory ()
+  (ggtags-ignore-file-error
+    (with-temp-buffer
+      (when (zerop (call-process "global" nil (list t nil) nil "-pr"))
+        (file-name-as-directory
+         (comment-string-strip (buffer-string) t t))))))
+
+(defun ggtags-check-root-directory ()
+  (assert (ggtags-root-directory) nil "File GTAGS not found"))
+
+(defun ggtags-ensure-root-directory ()
+  (or (ggtags-root-directory)
+      (if (yes-or-no-p "File GTAGS not found; run gtags? ")
+          (let ((root (read-directory-name "Directory: " nil nil t)))
+            (assert (not (zerop (length root))) nil "No directory chosen")
+            (ggtags-ignore-file-error
+              (with-temp-buffer
+                (if (zerop (let ((default-directory
+                                   (file-name-as-directory root)))
+                             (call-process "gtags" nil t)))
+                    (message "File GTAGS generated in `%s'"
+                             (ggtags-root-directory))
+                  (error "%s" (comment-string-strip (buffer-string) t t))))))
+        (error "Aborted"))))
+
+;;;###autoload
+(defun ggtags-tag-names (&optional prefix)
+  "Get a list of tag names starting with PREFIX."
+  (let ((root (ggtags-root-directory)))
+    (when (and root (ggtags-cache-dirty-p root))
+      (if (zerop (call-process "global" nil nil nil "-u"))
+          (ggtags-cache-mark-dirty root nil)
+        (message "ggtags: error running 'global -u'")))
+    (if (ggtags-cache-stale-p root)
+        (let ((tags (ggtags-ignore-file-error
+                      (split-string
+                       (with-output-to-string
+                         (call-process "global" nil (list standard-output nil)
+                                       nil "-c" (or prefix "")))))))
+          (when tags
+            (ggtags-cache-set root tags))
+          tags)
+      (cadr (ggtags-cache-get root)))))
+
+(defun ggtags-read-tag (&optional reference)
+  (ggtags-ensure-root-directory)
+  (let* ((tags (ggtags-tag-names))
+         (sym (thing-at-point 'symbol))
+         (default (and (member sym tags) sym)))
+    (setq ggtags-current-tag-name
+          (completing-read
+           (format (if default
+                       "%s for tag (default %s): "
+                     "%s for tag: ")
+                   (if reference "Reference" "Definition") default)
+           tags nil t nil nil default))))
+
+;;;###autoload
+(defun ggtags-find-tag (name &optional reference)
+  (interactive (list (ggtags-read-tag current-prefix-arg)
+                     current-prefix-arg))
+  (ggtags-check-root-directory)
+  (ggtags-navigation-mode +1)
+  (ring-insert find-tag-marker-ring (point-marker))
+  (let ((split-window-preferred-function
+         (lambda (w) (split-window (frame-root-window w))))
+        (default-directory (ggtags-root-directory)))
+    (compilation-start (format "global -v%s --result=grep \"%s\""
+                               (if reference "r" "") name)
+                       'ggtags-global-mode)))
+
+(defun ggtags-find-tag-resume ()
+  (interactive)
+  (ggtags-ensure-global-buffer
+    (ggtags-navigation-mode +1)
+    (compile-goto-error)))
+
+(defvar ggtags-tag-overlay nil)
+(make-variable-buffer-local 'ggtags-tag-overlay)
+
+(defun ggtags-highlight-tag-at-point ()
+  (unless (overlayp ggtags-tag-overlay)
+    (setq ggtags-tag-overlay (make-overlay (point) (point)))
+    (overlay-put ggtags-tag-overlay 'ggtags t))
+  (let ((bounds (bounds-of-thing-at-point 'symbol)))
+    (cond
+     ((not bounds)
+      (overlay-put ggtags-tag-overlay 'face nil)
+      (move-overlay ggtags-tag-overlay (point) (point)))
+     ((notany (lambda (o)
+                (overlay-get o 'ggtags))
+              (overlays-at (car bounds)))
+      (move-overlay ggtags-tag-overlay (car bounds) (cdr bounds))
+      (overlay-put ggtags-tag-overlay 'face
+                   (when (member (buffer-substring (car bounds) (cdr bounds))
+                                 (ggtags-tag-names))
+                     'ggtags-highlight))
+      (overlay-put ggtags-tag-overlay 'window t)))))
+
+(defun ggtags-global-exit-message-function (_process-status exit-status msg)
+  (let ((count (save-excursion
+                 (goto-char (point-min))
+                 (and (re-search-forward "^\\([0-9]+\\) objects? located" nil 
t)
+                      (string-to-number (match-string 1))))))
+    (cons (if (> exit-status 0)
+              msg
+            (format "found %d %s" count (if (= count 1) "match" "matches")))
+          exit-status)))
+
+(defun ggtags-abbreviate-file (start end)
+  (let ((inhibit-read-only t)
+        (amount (if (numberp ggtags-global-abbreviate-filename)
+                    (- (- end start) ggtags-global-abbreviate-filename)
+                  999))
+        (advance-word (lambda ()
+                        "Return the length of the text made invisible."
+                        (let ((wend (min end (progn (forward-word 1) (point))))
+                              (wbeg (max start (progn (backward-word 1) 
(point)))))
+                          (goto-char wend)
+                          (if (<= (- wend wbeg) 1)
+                              0
+                            (put-text-property (1+ wbeg) wend 'invisible t)
+                            (1- (- wend wbeg)))))))
+    (goto-char start)
+    (while (and (> amount 0) (> end (point)))
+      (decf amount (funcall advance-word)))))
+
+(defun ggtags-abbreviate-files (start end)
+  (goto-char start)
+  (when ggtags-global-abbreviate-filename
+    (while (re-search-forward "^\\([^:\n]+\\):[0-9]+:" end t)
+      (when (or (not (numberp ggtags-global-abbreviate-filename))
+                (> (length (match-string 1))
+                   ggtags-global-abbreviate-filename))
+        (ggtags-abbreviate-file (match-beginning 1) (match-end 1))))))
+
+(defun ggtags-handle-single-match (buf _how)
+  (unless (or (not ggtags-auto-jump-to-first-match)
+              (save-excursion
+                (goto-char (point-min))
+                (ignore-errors
+                  (goto-char (compilation-next-single-property-change
+                              (point) 'compilation-message))
+                  (end-of-line)
+                  (compilation-next-single-property-change
+                   (point) 'compilation-message))))
+    (ggtags-navigation-mode -1)
+    ;; 0.5s delay for `ggtags-auto-jump-to-first-match'
+    (ggtags-navigation-mode-cleanup buf 0.5)))
+
+(define-compilation-mode ggtags-global-mode "Global"
+  "A mode for showing outputs from gnu global."
+  (setq-local compilation-auto-jump-to-first-error
+              ggtags-auto-jump-to-first-match)
+  (setq-local compilation-scroll-output 'first-error)
+  (setq-local compilation-disable-input t)
+  (setq-local compilation-always-kill t)
+  (setq-local compilation-error-face 'compilation-info)
+  (setq-local compilation-exit-message-function
+              'ggtags-global-exit-message-function)
+  (setq-local truncate-lines t)
+  (jit-lock-register #'ggtags-abbreviate-files)
+  (add-hook 'compilation-finish-functions 'ggtags-handle-single-match nil t)
+  (define-key ggtags-global-mode-map "o" 'visible-mode))
+
+(defvar ggtags-navigation-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\M-n" 'next-error)
+    (define-key map "\M-p" 'previous-error)
+    (define-key map "\M-}" 'ggtags-navigation-next-file)
+    (define-key map "\M-{" 'ggtags-navigation-previous-file)
+    (define-key map "\M-o" 'ggtags-navigation-visible-mode)
+    (define-key map "\r" 'ggtags-navigation-mode-done)
+    ;; Intercept M-. and M-* keys
+    (define-key map [remap pop-tag-mark] 'ggtags-navigation-mode-abort)
+    (define-key map [remap ggtags-find-tag] 'undefined)
+    map))
+
+(defun ggtags-move-to-tag (&optional name)
+  "Move to NAME tag in current line."
+  (let ((orig (point))
+        (tag (or name ggtags-current-tag-name)))
+    (beginning-of-line)
+    (if (and tag (re-search-forward
+                  (concat "\\_<" (regexp-quote tag) "\\_>")
+                  (line-end-position)
+                  t))
+        (goto-char (match-beginning 0))
+      (goto-char orig))))
+
+(defun ggtags-navigation-mode-cleanup (&optional buf time)
+  (let ((buf (or buf compilation-last-buffer)))
+    (and (buffer-live-p buf)
+         (with-current-buffer buf
+           (when (get-buffer-process (current-buffer))
+             (kill-compilation))
+           (when (and (derived-mode-p 'ggtags-global-mode)
+                      (get-buffer-window))
+             (delete-window (get-buffer-window)))
+           (and time (run-with-idle-timer time nil
+                                          'kill-buffer (current-buffer)))))))
+
+(defun ggtags-navigation-mode-done ()
+  (interactive)
+  (ggtags-navigation-mode -1)
+  (ggtags-navigation-mode-cleanup))
+
+(defun ggtags-navigation-mode-abort ()
+  (interactive)
+  (pop-tag-mark)
+  (ggtags-navigation-mode -1)
+  (ggtags-navigation-mode-cleanup nil 0))
+
+(defun ggtags-navigation-next-file (n)
+  (interactive "p")
+  (ggtags-ensure-global-buffer
+    (compilation-next-file n)
+    (compile-goto-error)))
+
+(defun ggtags-navigation-previous-file (n)
+  (interactive "p")
+  (ggtags-navigation-next-file (- n)))
+
+(defun ggtags-navigation-visible-mode (&optional arg)
+  (interactive (list (or current-prefix-arg 'toggle)))
+  (ggtags-ensure-global-buffer
+    (visible-mode arg)))
+
+(define-minor-mode ggtags-navigation-mode nil
+  :lighter (" GG[" (:propertize "n" face error) "]")
+  :global t
+  (if ggtags-navigation-mode
+      (progn
+        (add-hook 'next-error-hook 'ggtags-move-to-tag)
+        (add-hook 'minibuffer-setup-hook
+                  'ggtags-minibuffer-setup-function nil t))
+    (remove-hook 'next-error-hook 'ggtags-move-to-tag)
+    (remove-hook 'minibuffer-setup-hook 'ggtags-minibuffer-setup-function t)))
+
+(defun ggtags-minibuffer-setup-function ()
+  ;; Disable ggtags-navigation-mode in minibuffer.
+  (setq-local ggtags-navigation-mode nil))
+
+(defun ggtags-kill-file-buffers (&optional interactive)
+  "Kill all buffers visiting files in the root directory."
+  (interactive "p")
+  (ggtags-check-root-directory)
+  (let ((root (ggtags-root-directory))
+        (count 0))
+    (dolist (buf (buffer-list))
+      (let ((file (and (buffer-live-p buf)
+                       (not (eq buf (current-buffer)))
+                       (buffer-file-name buf))))
+        (when (and file (file-in-directory-p (file-truename file) root))
+          (and (kill-buffer buf)
+               (incf count)))))
+    (and interactive
+         (message "%d %s killed" count (if (= count 1) "buffer" "buffers")))))
+
+(defun ggtags-after-save-function ()
+  (let ((root (ggtags-root-directory)))
+    (and root (ggtags-cache-mark-dirty root t))))
+
+(defvar ggtags-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\M-." 'ggtags-find-tag)
+    (define-key map "\C-c\M-n" 'ggtags-find-tag-resume)
+    (define-key map "\C-c\M-k" 'ggtags-kill-file-buffers)
+    map))
+
+;;;###autoload
+(define-minor-mode ggtags-mode nil
+  :lighter (:eval (if ggtags-navigation-mode "" " GG"))
+  (if ggtags-mode
+      (progn
+        (unless (ggtags-root-directory)
+          (funcall (if (fboundp 'user-error) 'user-error 'message)
+                   "File GTAGS not found"))
+        (add-hook 'after-save-hook 'ggtags-after-save-function nil t)
+        (add-hook 'post-command-hook 'ggtags-highlight-tag-at-point nil t))
+    (remove-hook 'after-save-hook 'ggtags-after-save-function t)
+    (remove-hook 'post-command-hook 'ggtags-highlight-tag-at-point t)
+    (and (overlayp ggtags-tag-overlay)
+         (delete-overlay ggtags-tag-overlay))
+    (setq ggtags-tag-overlay nil)))
+
+;;; imenu
+(defun ggtags-goto-imenu-index (name line &rest _args)
+  (save-restriction
+    (widen)
+    (goto-char (point-min))
+    (forward-line (1- line))
+    (ggtags-move-to-tag name)))
+
+;; NOTE: `ggtags-build-imenu-index' is signficantly faster and more
+;; precise than the similar feature provided by cc mode. Tested with
+;; ClassFileWriter.java of the rhino project.
+
+;;;###autoload
+(defun ggtags-build-imenu-index ()
+  "A function suitable for `imenu-create-index-function'."
+  (when buffer-file-name
+    (let ((file (file-truename buffer-file-name)))
+      (ggtags-ignore-file-error
+        (with-temp-buffer
+          (when (zerop (call-process "global" nil t nil "-f" file))
+            (goto-char (point-min))
+            (loop while (re-search-forward
+                         "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)" nil t)
+                  collect (list (match-string 1)
+                                (string-to-number (match-string 2))
+                                'ggtags-goto-imenu-index))))))))
+
+(provide 'ggtags)
+;;; ggtags.el ends here

commit ecadddfd280bbd9239952ea06e24b995a7f57fb2
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jan 26 12:43:38 2013 +0100

    Fix scan and bob errors.

diff --git a/eldoc-eval.el b/eldoc-eval.el
index 609c138..ebd2a74 100644
--- a/eldoc-eval.el
+++ b/eldoc-eval.el
@@ -149,6 +149,8 @@ See `with-eldoc-in-minibuffer'."
                               (eldoc-get-fnsym-args-string
                                (car info-fn) (cadr info-fn)))))
             (when doc (funcall eldoc-in-minibuffer-show-fn doc))))
+      (scan-error nil)
+      (beginning-of-buffer nil)
       (error (and debug-on-error (message "Eldoc in minibuffer error: %S" 
err))))))
 
 (defun eval-expression-with-eldoc ()

commit 3baf07adedffade081703ce45059b4a3182e0865
Merge: 540578b 1fa14bb
Author: Andrew Hyatt <address@hidden>
Date:   Wed Jan 23 18:48:29 2013 -0800

    Merge pull request #28 from jscheid/master
    
    Improve error display in default error handler


commit 1fa14bb71df4b0fabc123234a517533a19077f6d
Author: Julian Scheid <address@hidden>
Date:   Wed Jan 23 21:11:07 2013 +0100

    Improve error display in default error handler.
    
    - Pretty-print the error message, and include the error type.  Previously, 
only
      the error arguments were printed so that e.g. `end-of-buffer' would be
      rendered just as "nil".  Pretty-printing makes the output of the default 
error
      handler consistent with default error output.
    
    - Use `display-warning' rather than `message'.  Rationale: the error handler
      might be called many times in quick succession, overwriting previous 
messages.
      Also, the messages output by the error handler might be overwritten by
      messages emitted by other parts of the code (e.g. by websocket callbacks
      invoked after the error occurred.)
    
      Although past messages are always available in the *Messages* buffer, with
      `display-warning' errors are displayed more prominently since the 
*Warnings*
      buffer is unburied whenever new errors are printed.

diff --git a/websocket-test.el b/websocket-test.el
index 19746fd..f7c5936 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -573,3 +573,24 @@
     (should (eq 'conn-b (websocket-conn (car closed-websockets))))
     (should (eq 1 (length websocket-server-websockets)))
     (should (eq 'conn-a (websocket-conn (car websocket-server-websockets))))))
+
+(ert-deftest websocket-default-error-handler ()
+  (flet ((try-error
+          (callback-type err expected-message)
+          (flet ((display-warning
+                  (type message &optional level buffer-name)
+                  (should (eq type 'websocket))
+                  (should (eq level :error))
+                  (should (string= message expected-message))))
+            (websocket-default-error-handler nil
+                                             callback-type
+                                             err))))
+    (try-error
+     'on-message
+     '(end-of-buffer)
+     "in callback `on-message': End of buffer")
+
+    (try-error
+     'on-close
+     '(wrong-number-of-arguments 1 2)
+     "in callback `on-close': Wrong number of arguments: 1, 2")))
diff --git a/websocket.el b/websocket.el
index b5f4c70..8fda4fd 100644
--- a/websocket.el
+++ b/websocket.el
@@ -363,9 +363,25 @@ the frame finishes.  If the frame is not completed, return 
NIL."
        :length (if payloadp payload-end 1)
        :completep (> fin 0)))))
 
+(defun websocket-format-error (err)
+  "Format an error message like command level does. ERR should be
+a cons of error symbol and error data."
+
+  ;; Formatting code adapted from `edebug-report-error'
+  (concat (or (get (car err) 'error-message)
+              (format "peculiar error (%s)" (car err)))
+          (when (cdr err)
+            (format ": %s"
+                    (mapconcat #'prin1-to-string
+                               (cdr err) ", ")))))
+
 (defun websocket-default-error-handler (websocket type err)
   "The default error handler used to handle errors in callbacks."
-  (message "Error found in callback `%S': %s" type (cdr err)))
+  (display-warning 'websocket
+                   (format "in callback `%S': %s"
+                           type
+                           (websocket-format-error err))
+                   :error))
 
 ;; Error symbols in use by the library
 (put 'websocket-unsupported-protocol 'error-conditions

commit f4ae1de92f40837e67af46378fd27d02c0e6bd22
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jan 13 20:24:58 2013 +0100

    Initial commit, add files.

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/eldoc-eval.el b/eldoc-eval.el
new file mode 100644
index 0000000..609c138
--- /dev/null
+++ b/eldoc-eval.el
@@ -0,0 +1,165 @@
+;;; eldoc-eval.el -- Show eldoc when using M-:
+
+;; Copyright (C) 2011 Free Software Foundation, Inc.
+
+;; Author: Thierry Volpiatto <address@hidden>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+(require 'eldoc)
+
+
+;;; Minibuffer support.
+;;  Enable displaying eldoc info in something else
+;;  Than minibuffer when this one is in use.
+;;
+(defcustom eldoc-in-minibuffer t
+  "Turn on eldoc in minibuffer."
+  :group 'eldoc
+  :type 'bolean)
+
+(defcustom eldoc-in-minibuffer-show-fn 'eldoc-show-in-mode-line
+  "A function to display eldoc info.
+Should take one arg: the string to display"
+  :group 'eldoc
+  :type 'function)
+
+(defcustom eldoc-show-in-mode-line-delay 12
+  "The time we show eldoc when Emacs is idle."
+  :group 'eldoc
+  :type 'number)
+
+(defcustom eval-prefered-function 'pp-eval-expression
+  "Prefered function to use with `M-:'."
+  :group 'lisp
+  :type 'function)
+
+(defcustom  eldoc-in-minibuffer-own-frame-p nil
+  "Whether minibuffer have own frame or not."
+  :group 'lisp
+  :type 'boolean)
+
+;; Internal.
+(defvar eldoc-active-minibuffers-list nil
+  "Store actives minibuffers with eldoc enabled.")
+(defvar eldoc-mode-line-rolling-flag nil)
+
+(defun eldoc-store-minibuffer ()
+  "Store minibuffer buffer name in `eldoc-active-minibuffers-list'.
+This function is called by each minibuffer started with eldoc support.
+See `with-eldoc-in-minibuffer'."
+  (with-selected-window (minibuffer-window)
+    (push (buffer-name) eldoc-active-minibuffers-list)))
+
+(defmacro with-eldoc-in-minibuffer (&rest body)
+  "Enable eldoc support for minibuffer input that run in BODY."
+  (declare (indent 0) (debug t))
+  `(let ((timer (and eldoc-in-minibuffer
+                     (run-with-idle-timer
+                      eldoc-idle-delay
+                      'repeat 'eldoc-mode-in-minibuffer))))
+     (unwind-protect
+         (minibuffer-with-setup-hook
+             ;; When minibuffer is activated in body,
+             ;; store it.
+             'eldoc-store-minibuffer
+           ,@body)
+       (and timer (cancel-timer timer))
+       ;; Each time a minibuffer exit or abort
+       ;; his buffer is removed from stack,
+       ;; assuming we can only exit the active minibuffer
+       ;; on top of stack.
+       (setq eldoc-active-minibuffers-list
+             (cdr eldoc-active-minibuffers-list)))))
+
+(defun eldoc-current-buffer ()
+  "The `current-buffer' before activating minibuffer."
+  (with-selected-frame (last-nonminibuffer-frame)
+    (window-buffer
+     (cond (eldoc-in-minibuffer-own-frame-p
+            (selected-window))
+           ((fboundp 'window-in-direction)
+            (window-in-direction 
+             'above (minibuffer-window)))
+           (t (minibuffer-selected-window))))))
+
+(defun eldoc-show-in-mode-line (str)
+  "Display string STR in the mode-line next to minibuffer."
+  (let (mode-line-in-non-selected-windows)
+    (with-current-buffer (eldoc-current-buffer)
+      (make-local-variable 'mode-line-format)
+      (let ((mode-line-format (concat " " str)))
+        (eldoc-maybe-roll-message-in-mode-line mode-line-format))
+      (force-mode-line-update))))
+
+(defun eldoc-maybe-roll-message-in-mode-line (str)
+  (let* ((max (window-width (get-buffer-window (eldoc-current-buffer))))
+         (len (length str))
+         (tmp-str str))
+    (if (and (> len max) eldoc-mode-line-rolling-flag)
+        (while (sit-for 0.3)
+           (setq tmp-str (substring tmp-str 2)
+                 mode-line-format (concat tmp-str " [<]" str))
+           (force-mode-line-update nil)
+           (when (< (length tmp-str) 2) (setq tmp-str str)))
+        (force-mode-line-update nil)
+        (sit-for eldoc-show-in-mode-line-delay))))
+
+(defun eldoc-mode-line-toggle-rolling ()
+  (interactive)
+  (setq eldoc-mode-line-rolling-flag (not eldoc-mode-line-rolling-flag)))
+(define-key minibuffer-local-map (kbd "<C-M-right>") 
'eldoc-mode-line-toggle-rolling)
+
+(defun eldoc-mode-in-minibuffer ()
+  "Show eldoc for current minibuffer input."
+  (let ((buf (with-selected-window (minibuffer-window)
+               (buffer-name))))
+    ;; If this minibuffer have been started with
+    ;;`with-eldoc-in-minibuffer' give it eldoc support
+    ;; and update mode-line, otherwise do nothing.
+    (condition-case err
+        (when (member buf eldoc-active-minibuffers-list)
+          (let* ((str-all (with-current-buffer buf
+                            (minibuffer-completion-contents)))
+                 (sym     (when str-all
+                            (with-temp-buffer
+                              (insert str-all)
+                              (goto-char (point-max))
+                              (unless (looking-back ")\\|\"")
+                                (forward-char -1))
+                              (eldoc-current-symbol))))
+                 (info-fn (eldoc-fnsym-in-current-sexp))
+                 (doc     (or (eldoc-get-var-docstring sym)
+                              (eldoc-get-fnsym-args-string
+                               (car info-fn) (cadr info-fn)))))
+            (when doc (funcall eldoc-in-minibuffer-show-fn doc))))
+      (error (and debug-on-error (message "Eldoc in minibuffer error: %S" 
err))))))
+
+(defun eval-expression-with-eldoc ()
+  "Eval expression with eldoc support in mode-line."
+  (interactive)
+  (with-eldoc-in-minibuffer
+    (call-interactively eval-prefered-function)))
+
+;; Bind it to `M-:'.
+(global-set-key [remap eval-expression] 'eval-expression-with-eldoc)
+
+
+(provide 'eldoc-eval)
+;;; eldoc-eval.el ends here

commit 086cacd47c24f1a8707a82689d5dec49656f7562
Author: Leo Liu <address@hidden>
Date:   Sun Jan 13 00:38:02 2013 +0800

    New command ack-yank-symbol-at-point and bind it to M-Y
    
    Thanks to address@hidden for request and testing.

diff --git a/README.rst b/README.rst
index 96cbb64..f0c656a 100644
--- a/README.rst
+++ b/README.rst
@@ -81,6 +81,8 @@ key bindings may be useful:
 
 - ``M-I`` => insert a template for case-insensitive file name search
 - ``M-G`` => insert a template for ``git grep``, ``hg grep`` or ``bzr grep``
+- ``M-Y`` => grab the symbol at point from the window before entering
+  the minibuffer
 - ``TAB`` => completion for ack options
 
 Bugs
diff --git a/ack.el b/ack.el
index d58a7ff..6b1655d 100644
--- a/ack.el
+++ b/ack.el
@@ -1,6 +1,6 @@
 ;;; ack.el --- Emacs interface to ack
 
-;; Copyright (C) 2012  Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Version: 0.8
@@ -308,6 +308,16 @@ This gets tacked on the end of the generated expressions.")
     (delete-minibuffer-contents)
     (skeleton-insert '(nil cmd " '" _ "'"))))
 
+(defun ack-yank-symbol-at-point ()
+  "Yank the symbol from the window before entering the minibuffer."
+  (interactive)
+  (let ((symbol (and (minibuffer-selected-window)
+                     (with-current-buffer
+                         (window-buffer (minibuffer-selected-window))
+                       (thing-at-point 'symbol)))))
+    (if symbol (insert symbol)
+      (minibuffer-message "No symbol found"))))
+
 (defvar ack-minibuffer-local-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
@@ -316,6 +326,7 @@ This gets tacked on the end of the generated expressions.")
                            'pcomplete))
     (define-key map "\M-I" 'ack-skel-file)
     (define-key map "\M-G" 'ack-skel-vc-grep)
+    (define-key map "\M-Y" 'ack-yank-symbol-at-point)
     (define-key map "'" 'skeleton-pair-insert-maybe)
     map)
   "Keymap used for reading `ack' command and args in minibuffer.")
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index ea504a8..766168a 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -1,6 +1,6 @@
 ;;; pcmpl-ack.el --- completion for ack tool
 
-;; Copyright (C) 2012  Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2013  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience

commit ec0427470f8fe5e2a10c7658b8689852afe2a890
Author: Dmitry Gutov <address@hidden>
Date:   Sat Dec 29 07:25:31 2012 +0400

    Don't use overriding-terminal-local-map
    
    Use emulation-mode-map-alists instead.
    
    This way, all non-shadowed bindings (like paredit's) are intact.
    
    Also had to change tab and return's key notations in the map definition,
    because otherwise they were still captured by yasnippet and autopair,
    respectively.

diff --git a/company.el b/company.el
index d001a9f..317e1a7 100644
--- a/company.el
+++ b/company.el
@@ -512,8 +512,8 @@ The work-around consists of adding a newline.")
     (define-key keymap [mouse-3] 'company-select-mouse)
     (define-key keymap [up-mouse-1] 'ignore)
     (define-key keymap [up-mouse-3] 'ignore)
-    (define-key keymap "\C-m" 'company-complete-selection)
-    (define-key keymap "\t" 'company-complete-common)
+    (define-key keymap [return] 'company-complete-selection)
+    (define-key keymap [tab] 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     (define-key keymap "\C-w" 'company-show-location)
     (define-key keymap "\C-s" 'company-search-candidates)
@@ -598,31 +598,28 @@ keymap during active completions (`company-active-map'):
 
 ;;; keymaps 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-overriding-keymap-bound nil)
-(make-variable-buffer-local 'company-overriding-keymap-bound)
-
-(defvar company-old-keymap nil)
-(make-variable-buffer-local 'company-old-keymap)
-
 (defvar company-my-keymap nil)
 (make-variable-buffer-local 'company-my-keymap)
 
+(defvar company-emulation-alist '((t . nil)))
+
 (defsubst company-enable-overriding-keymap (keymap)
-  (setq company-my-keymap keymap)
-  (when company-overriding-keymap-bound
-    (company-uninstall-map)))
+  (company-uninstall-map)
+  (setq company-my-keymap keymap))
+
+(defun company-ensure-emulation-alist ()
+  (unless (eq 'company-emulation-alist (car emulation-mode-map-alists))
+    (setq emulation-mode-map-alists
+          (cons 'company-emulation-alist
+                (delq 'company-emulation-alist emulation-mode-map-alists)))))
 
 (defun company-install-map ()
-  (unless (or company-overriding-keymap-bound
+  (unless (or (cdar company-emulation-alist)
               (null company-my-keymap))
-    (setq company-old-keymap overriding-terminal-local-map
-          overriding-terminal-local-map company-my-keymap
-          company-overriding-keymap-bound t)))
+    (setf (cdar company-emulation-alist) company-my-keymap)))
 
 (defun company-uninstall-map ()
-  (when (eq overriding-terminal-local-map company-my-keymap)
-    (setq overriding-terminal-local-map company-old-keymap
-          company-overriding-keymap-bound nil)))
+  (setf (cdar company-emulation-alist) nil))
 
 ;; Hack:
 ;; Emacs calculates the active keymaps before reading the event.  That means we
@@ -1046,6 +1043,7 @@ can retrieve meta-data for them."
       (setq company-added-newline (buffer-chars-modified-tick)))
     (setq company-point (point)
           company--point-max (point-max))
+    (company-ensure-emulation-alist)
     (company-enable-overriding-keymap company-active-map)
     (company-call-frontends 'update)))
 

commit 843455d84ba4de1140232b4f540fa50105081e4f
Author: Dmitry Gutov <address@hidden>
Date:   Thu Dec 27 04:55:13 2012 +0400

    * company-elisp: complete features and faces,
      find docs and definitions of non-function symbols properly

diff --git a/company-elisp.el b/company-elisp.el
index 1e2b171..1073f28 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -38,7 +38,9 @@ Functions are offered for completion only after ' and \(."
 
 (defun company-elisp-predicate (symbol)
   (or (boundp symbol)
-      (fboundp symbol)))
+      (fboundp symbol)
+      (facep symbol)
+      (featurep symbol)))
 
 (defvar company-elisp-parse-limit 30)
 (defvar company-elisp-parse-depth 100)
@@ -116,13 +118,22 @@ Functions are offered for completion only after ' and \(."
     (meta (company-elisp-doc arg))
     (doc-buffer (let ((symbol (intern arg)))
                   (save-window-excursion
-                    (when (or (ignore-errors (describe-function symbol))
-                              (ignore-errors (describe-variable symbol)))
+                    (ignore-errors
+                      (cond
+                       ((fboundp symbol) (describe-function symbol))
+                       ((boundp symbol) (describe-variable symbol))
+                       ((featurep symbol) (describe-package symbol))
+                       ((facep symbol) (describe-face symbol))
+                       (t (signal 'user-error nil)))
                       (help-buffer)))))
     (location (let ((sym (intern arg)))
-                (or (ignore-errors (find-definition-noselect sym nil))
-                    (ignore-errors (find-definition-noselect sym 'defvar))
-                    (ignore-errors (find-definition-noselect sym t)))))))
+                (cond
+                 ((fboundp sym) (find-definition-noselect sym nil))
+                 ((boundp sym) (find-definition-noselect sym 'defvar))
+                 ((featurep sym) (cons (find-file-noselect (find-library-name
+                                                            (symbol-name sym)))
+                                       0))
+                 ((facep sym) (find-definition-noselect sym 'defface)))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here

commit 7630a844c3453409825364e0ccb1504b1efa4b08
Author: Dmitry Gutov <address@hidden>
Date:   Wed Dec 26 07:33:43 2012 +0400

    Returns -> Return

diff --git a/js2-mode.el b/js2-mode.el
index b35f76d..702b32c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6693,7 +6693,7 @@ that it's an external variable, which must also be in the 
top-level scope."
      (t t))))
 
 (defun js2-wrapper-function-p (node)
-  "Returns t if NODE is a function expression that's immediately invoked.
+  "Return t if NODE is a function expression that's immediately invoked.
 NODE must be `js2-function-node'."
   (let ((parent (js2-node-parent node)))
     (or
@@ -6952,7 +6952,7 @@ The flags, if any, are saved in 
`js2-current-flagged-token'."
       tt)))  ; return unflagged token
 
 (defun js2-peek-flagged-token ()
-  "Returns the current token along with any flags set for it."
+  "Return the current token along with any flags set for it."
   (js2-peek-token)
   js2-current-flagged-token)
 
@@ -9681,7 +9681,7 @@ indented to the same column as the current line."
                    (= (current-indentation) saved-indent))))))))
 
 (defun js2-multiline-decl-indentation ()
-  "Returns the declaration indentation column if the current line belongs
+  "Return the declaration indentation column if the current line belongs
 to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
   (let (forward-sexp-function ; use Lisp version
         at-opening-bracket)

commit eb89f06d7e4329f5041dce998f2e093259c6b4ef
Author: Dmitry Gutov <address@hidden>
Date:   Wed Dec 26 07:26:21 2012 +0400

    Toggles -> Toggle

diff --git a/js2-mode.el b/js2-mode.el
index 782dbc1..b35f76d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10705,7 +10705,7 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
     (js2-indent-line)))
 
 (defun js2-beginning-of-line ()
-  "Toggles point between bol and first non-whitespace char in line.
+  "Toggle point between bol and first non-whitespace char in line.
 Also moves past comment delimiters when inside comments."
   (interactive)
   (let (node beg)
@@ -10725,7 +10725,7 @@ Also moves past comment delimiters when inside 
comments."
       (goto-char (point-at-bol))))))
 
 (defun js2-end-of-line ()
-  "Toggles point between eol and last non-whitespace char in line."
+  "Toggle point between eol and last non-whitespace char in line."
   (interactive)
   (if (eolp)
       (skip-chars-backward " \t")

commit e378db4d306907e8af78bb1c766d5dbddbbbf4f2
Author: Dmitry Gutov <address@hidden>
Date:   Tue Dec 25 04:08:50 2012 +0400

    2011, too

diff --git a/js2-mode.el b/js2-mode.el
index 4d25e6b..782dbc1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1,6 +1,6 @@
 ;;; js2-mode.el --- Improved JavaScript editing mode
 
-;; Copyright (C) 2009, 2012  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2011, 2012  Free Software Foundation, Inc.
 
 ;; Author: Steve Yegge <address@hidden>
 ;;         mooz <address@hidden>

commit 8b78584fd26a465f66ecd3c32c5f4106823bae51
Author: Dmitry Gutov <address@hidden>
Date:   Tue Dec 25 03:23:00 2012 +0400

    Tweak headers, remove extra vars, set the version to 1.0

diff --git a/js2-mode.el b/js2-mode.el
index b9fb5ed..5502730 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1,12 +1,12 @@
-;;; js2-mode.el --- an improved JavaScript editing mode
+;;; js2-mode.el --- Improved JavaScript editing mode
 
-;; Copyright (C) 2009  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2012  Free Software Foundation, Inc.
 
-;; Author:  Steve Yegge <address@hidden>
-;; Contributors:  mooz <address@hidden>
-;;                Dmitry Gutov <address@hidden>
-;; Version:  See `js2-mode-version'
-;; Keywords:  languages, javascript
+;; Author: Steve Yegge <address@hidden>
+;;         mooz <address@hidden>
+;;         Dmitry Gutov <address@hidden>
+;; Version: 1.0
+;; Keywords: languages, javascript
 
 ;; This file is part of GNU Emacs.
 
@@ -28,7 +28,7 @@
 ;; This JavaScript editing mode supports:
 
 ;;  - strict recognition of the Ecma-262 language standard
-;;  - support for most Rhino and SpiderMonkey extensions from 1.5 to 1.8
+;;  - support for most Rhino and SpiderMonkey extensions from 1.5 and up
 ;;  - parsing support for ECMAScript for XML (E4X, ECMA-357)
 ;;  - accurate syntax highlighting using a recursive-descent parser
 ;;  - on-the-fly reporting of syntax errors and strict-mode warnings
@@ -309,12 +309,6 @@ end of the line, otherwise, at the beginning of the next 
line."
   :type '(choice (const t) (const eol) (const nil))
   :group 'js2-mode)
 
-(defcustom js2-mode-squeeze-spaces t
-  "Non-nil to normalize whitespace when filling in comments.
-Multiple runs of spaces are converted to a single space."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-mode-show-parse-errors t
   "True to highlight parse errors."
   :type 'boolean
@@ -470,9 +464,6 @@ which doesn't seem particularly useful, but Rhino permits 
it."
   :type 'boolean
   :group 'js2-mode)
 
-(defvar js2-mode-version 20101228
-  "Release number for `js2-mode'.")
-
 ;; scanner variables
 
 (defmacro js2-deflocal (name value &optional comment)
@@ -7081,8 +7072,8 @@ i.e. one or more nodes, and an integer position as the 
list tail."
 
 ;;; Parser
 
-(defconst js2-version "1.8.0"
-  "Version of JavaScript supported, plus minor js2 version.")
+(defconst js2-version "1.8.5"
+  "Version of JavaScript supported.")
 
 (defmacro js2-record-face (face)
   "Record a style run of FACE for the current token."

commit bc1e159ee95c120041c972b147bbe81a3f178bf5
Author: Dmitry Gutov <address@hidden>
Date:   Tue Dec 25 03:20:16 2012 +0400

    Tweak headers, remove extra variables, set the version to 1.1

diff --git a/js2-mode.el b/js2-mode.el
index 0e4d518..4d25e6b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2,11 +2,12 @@
 
 ;; Copyright (C) 2009, 2012  Free Software Foundation, Inc.
 
-;; Author:  Steve Yegge <address@hidden>
-;; Contributors:  mooz <address@hidden>
-;;                Dmitry Gutov <address@hidden>
-;; Version:  See `js2-mode-version'
-;; Keywords:  languages, javascript
+;; Author: Steve Yegge <address@hidden>
+;;         mooz <address@hidden>
+;;         Dmitry Gutov <address@hidden>
+;; Version: 1.1
+;; Keywords: languages, javascript
+;; Package-Requires: ((emacs "24.1"))
 
 ;; This file is part of GNU Emacs.
 
@@ -28,7 +29,7 @@
 ;; This JavaScript editing mode supports:
 
 ;;  - strict recognition of the Ecma-262 language standard
-;;  - support for most Rhino and SpiderMonkey extensions from 1.5 to 1.8
+;;  - support for most Rhino and SpiderMonkey extensions from 1.5 and up
 ;;  - parsing support for ECMAScript for XML (E4X, ECMA-357)
 ;;  - accurate syntax highlighting using a recursive-descent parser
 ;;  - on-the-fly reporting of syntax errors and strict-mode warnings
@@ -40,7 +41,6 @@
 ;;    - show some or all block comments as /*...*/
 ;;  - context-sensitive menu bar and popup menus
 ;;  - code browsing using the `imenu' package
-;;  - typing helpers such as automatic insertion of matching braces/parens
 ;;  - many customization options
 
 ;; Installation:
@@ -83,7 +83,6 @@
 
 (eval-and-compile
   (require 'cc-mode)     ; (only) for `c-populate-syntax-table'
-  (require 'cc-langs)    ; it's here in Emacs 21...
   (require 'cc-engine))  ; for `c-paragraph-start' et. al.
 
 (defvar electric-layout-rules)
@@ -272,11 +271,6 @@ If `js2-dynamic-idle-timer-adjust' is 0 or negative,
   :type 'number
   :group 'js2-mode)
 
-(defcustom js2-mode-escape-quotes t
-  "Non-nil to disable automatic quote-escaping inside strings."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-concat-multiline-strings t
   "Non-nil to automatically turn a newline in mid-string into a
 string concatenation.  When `eol', the '+' will be inserted at the
@@ -284,12 +278,6 @@ end of the line, otherwise, at the beginning of the next 
line."
   :type '(choice (const t) (const eol) (const nil))
   :group 'js2-mode)
 
-(defcustom js2-mode-squeeze-spaces t
-  "Non-nil to normalize whitespace when filling in comments.
-Multiple runs of spaces are converted to a single space."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-mode-show-parse-errors t
   "True to highlight parse errors."
   :type 'boolean
@@ -440,9 +428,6 @@ which doesn't seem particularly useful, but Rhino permits 
it."
   :type 'boolean
   :group 'js2-mode)
 
-(defvar js2-mode-version 20120416
-  "Release number for `js2-mode'.")
-
 ;; scanner variables
 
 (defmacro js2-deflocal (name value &optional comment)
@@ -6891,8 +6876,8 @@ i.e. one or more nodes, and an integer position as the 
list tail."
 
 ;;; Parser
 
-(defconst js2-version "1.8.0"
-  "Version of JavaScript supported, plus minor js2 version.")
+(defconst js2-version "1.8.5"
+  "Version of JavaScript supported.")
 
 (defmacro js2-record-face (face)
   "Record a style run of FACE for the current token."

commit 139014fb75e81fe1d6f355543d85de898e61d555
Author: Dmitry Gutov <address@hidden>
Date:   Tue Dec 25 02:45:13 2012 +0400

    Close #79

diff --git a/js2-mode.el b/js2-mode.el
index d2bb052..b9fb5ed 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1174,9 +1174,6 @@ another file, or you've got a potential bug."
     (define-key map (kbd "C-c C-o") #'js2-mode-toggle-element)
     (define-key map (kbd "C-c C-w") #'js2-mode-toggle-warnings-and-errors)
     (define-key map (kbd "C-c C-`") #'js2-next-error)
-    ;; also define user's preference for next-error, if available
-    (if (setq keys (where-is-internal #'next-error))
-        (define-key map (car keys) #'js2-next-error))
     (define-key map (or (car (where-is-internal #'mark-defun))
                         (kbd "M-C-h"))
       #'js2-mark-defun)

commit bbaa2843a38bd689950e9263c4f4ba5747eb53ed
Merge: 40dbc69 a310dfc
Author: Dmitry Gutov <address@hidden>
Date:   Thu Dec 13 01:27:53 2012 +0400

    Merge branch 'master' into emacs24
    
    Conflicts:
        js2-mode.el


commit a310dfc91eec38ce2bf3553ef5bde2fe532b4505
Author: Dmitry Gutov <address@hidden>
Date:   Thu Dec 13 01:21:22 2012 +0400

    Fix #77, left over from #58
    
    Also, don't walk the tree unless js2-mode-show-overlay is t.

diff --git a/js2-mode.el b/js2-mode.el
index 1ba5318..d2bb052 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10648,10 +10648,10 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
   "Debugging aid:  highlight selected AST node on mouse click."
   (interactive "e")
   (mouse-set-point event)
-  (let ((node (js2-node-at-point))
-        beg
-        end)
-    (when js2-mode-show-overlay
+  (setq deactivate-mark t)
+  (when js2-mode-show-overlay
+    (let ((node (js2-node-at-point))
+          beg end)
       (if (null node)
           (message "No node found at location %s" (point))
         (setq beg (js2-node-abs-pos node)
@@ -10668,8 +10668,6 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                      (js2-node-short-name (js2-node-parent node))
                    "nil"))))))
 
-(put 'js2-mode-show-node 'CUA 'move)
-
 (defun js2-mode-hide-overlay (&optional p1 p2)
   "Remove the debugging overlay when the point moves.
 P1 and P2 are the old and new values of point, respectively."

commit 40dbc6935b8012a62e6f6af8048d5849a64edc6f
Merge: 1b19cbe 6b3f092
Author: Dmitry Gutov <address@hidden>
Date:   Thu Dec 13 01:17:07 2012 +0400

    Pretend to merge branch 'master' into emacs24
    
    Conflicts:
        README.md
        js2-mode.el


commit 803ff3611c32b0cf677f565e4d501a686bb705ae
Author: Leo Liu <address@hidden>
Date:   Tue Nov 13 12:56:49 2012 +0800

    New user option ack-buffer-name-function
    
    Thanks to address@hidden for request and testing.

diff --git a/ack.el b/ack.el
index 8e85531..d58a7ff 100644
--- a/ack.el
+++ b/ack.el
@@ -57,6 +57,12 @@ environment variable and ~/.ackrc, which you can disable by 
the
   :type 'string
   :group 'ack)
 
+(defcustom ack-buffer-name-function nil
+  "If non-nil, a function to compute the name of an ack buffer.
+See `compilation-buffer-name-function' for details."
+  :type '(choice function (const nil))
+  :group 'ack)
+
 (defcustom ack-vc-grep-commands
   '((".git" . "git --no-pager grep --color -n -i")
     (".hg" . "hg grep -n -i")
@@ -364,7 +370,11 @@ minibuffer:
            project-root)))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))
-    (compilation-start command-args 'ack-mode)))
+    ;; Change to the compilation buffer so that `ack-buffer-name-function' can
+    ;; make use of `compilation-arguments'.
+    (with-current-buffer (compilation-start command-args 'ack-mode)
+      (when ack-buffer-name-function
+        (rename-buffer (funcall ack-buffer-name-function "ack"))))))
 
 (provide 'ack)
 ;;; ack.el ends here

commit 540578b749644cd6f4d97fc137dd9fce907dae68
Author: Andrew Hyatt <address@hidden>
Date:   Sat Oct 13 18:46:02 2012 -0400

    Add third client in the list of clients.  Now that we have three
    clients, bump version to 1.0.

diff --git a/README.org b/README.org
index 3734b68..a8d42f8 100644
--- a/README.org
+++ b/README.org
@@ -11,19 +11,7 @@ An example of how to use the library is in the
 This library is compatible with emacs 23 and 24, although only emacs
 24 support secure websockets.
 
-* Version
-
-** Version 1.0 requiements
-This version should be usable, but needs the following:
-
-- 3 clients using this module.  Without this many clients, it's hard
-  to be sure the API is right, or there isn't a hidden bug in the
-  module.
-
-Notably, this project is experimenting with an eieio-based API (see
-the EIEIO branch).  Please send us any feedback about the API.
-
-** Version release checklist
+* Version release checklist
 
 Each version that is released should be checked with this checklist:
 
@@ -37,6 +25,7 @@ Each version that is released should be checked with this 
checklist:
 
 - [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]]
 - [[https://github.com/syohex/emacs-realtime-markdown-viewer][Emacs Realtime 
Markdown Viewer]]
+- [[https://github.com/jscheid/kite][Kite]]
 
 If you are using this module for your own emacs package, please let me
 know by editing this file, adding your project, and sending a pull
diff --git a/websocket.el b/websocket.el
index e96a904..b5f4c70 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication, Websocket, Server
-;; Version: 0.93.1
+;; Version: 1.0
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -101,7 +101,7 @@ same for the protocols.
   accept-string
   (inflight-input nil))
 
-(defvar websocket-version "0.93.1"
+(defvar websocket-version "1.0"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit a0a66f2f6a1edf5368251bca7e76cafe2232fd1f
Author: Leo Liu <address@hidden>
Date:   Mon Oct 8 22:21:47 2012 +0800

    Make minibuffer prompt more informative

diff --git a/ack.el b/ack.el
index d97335d..8e85531 100644
--- a/ack.el
+++ b/ack.el
@@ -267,6 +267,13 @@ This gets tacked on the end of the generated expressions.")
                 (ansi-color-apply-on-region beg ack--ansi-color-last-marker))
               nil))))))
 
+(defun ack-update-minibuffer-prompt (prompt)
+  "Visually replace minibuffer prompt with PROMPT."
+  (when (minibufferp)
+    (let ((inhibit-read-only t))
+      (put-text-property
+       (point-min) (minibuffer-prompt-end) 'display prompt))))
+
 (defun ack-skel-file ()
   "Insert a template for case-insensitive file name search."
   (interactive)
@@ -285,10 +292,13 @@ This gets tacked on the end of the generated 
expressions.")
          (root (or (ack-guess-project-root default-directory regexp)
                    (error "Cannot locate vc project root")))
          (which (car (directory-files root nil regexp)))
+         (backend (downcase (substring which 1)))
          (cmd (or (cdr (assoc which ack-vc-grep-commands))
-                  (error "No command provided for `%s grep'"
-                         (substring which 1)))))
+                  (error "No command provided for `%s grep'" backend))))
     (setq project-root root)
+    (ack-update-minibuffer-prompt
+     (format "Run %s grep in `%s': " backend
+             (file-name-nondirectory (directory-file-name project-root))))
     (delete-minibuffer-contents)
     (skeleton-insert '(nil cmd " '" _ "'"))))
 
@@ -338,16 +348,19 @@ minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (let ((project-root (funcall ack-default-directory-function
-                                current-prefix-arg))
+   (let ((project-root (or (funcall ack-default-directory-function
+                                    current-prefix-arg)
+                           default-directory))
          ;; Disable completion cycling; see http://debbugs.gnu.org/12221
          (completion-cycle-threshold nil))
      (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
                                            'shell-completion-vars
                                          'pcomplete-shell-setup)
-             (read-from-minibuffer "Run ack (like this): "
-                                   ack-command ack-minibuffer-local-map
-                                   nil 'ack-history))
+             (read-from-minibuffer
+              (format "Run ack in `%s': "
+                      (file-name-nondirectory
+                       (directory-file-name project-root)))
+              ack-command ack-minibuffer-local-map nil 'ack-history))
            project-root)))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))

commit 2583c1b67ff8abe6341bc7a1fc661eb40d75694a
Author: Leo Liu <address@hidden>
Date:   Mon Oct 8 17:20:29 2012 +0800

    Merge changes from GNU ELPA

diff --git a/README.rst b/README.rst
index f702340..96cbb64 100644
--- a/README.rst
+++ b/README.rst
@@ -72,9 +72,9 @@ options while ``M-x ack`` or in shell/eshell.
 Usage
 -----
 
-- ``M-x ack`` and provide a pattern to search.
-- ``C-u M-x ack`` like ``M-x ack`` but allow you to select a
-  directory to search.
+- Type ``M-x ack`` and provide a pattern to search.
+- Type ``C-u M-x ack`` to search from current project root.
+- Type ``C-u C-u M-x ack`` to interactively choose a directory to search.
 
 While reading ack command and args from the minibuffer, the following
 key bindings may be useful:
diff --git a/ack.el b/ack.el
index 78bfd81..d97335d 100644
--- a/ack.el
+++ b/ack.el
@@ -1,6 +1,6 @@
 ;;; ack.el --- Emacs interface to ack
 
-;; Copyright (C) 2012  Leo Liu
+;; Copyright (C) 2012  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Version: 0.8
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index dfac435..ea504a8 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -1,6 +1,6 @@
 ;;; pcmpl-ack.el --- completion for ack tool
 
-;; Copyright (C) 2012  Leo Liu
+;; Copyright (C) 2012  Free Software Foundation, Inc.
 
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience

commit 0fce282ff01c002509443372fec2279794f89cf4
Merge: b65328c 297244f
Author: Andrew Hyatt <address@hidden>
Date:   Sun Oct 7 20:48:30 2012 -0700

    Merge pull request #26 from tkf/better-wss-error-for-emacs-23
    
    Better wss error for emacs 23


commit 297244fcfd3766c1cd741b90d630d85f9d9a0258
Author: Takafumi Arakaki <address@hidden>
Date:   Sat Oct 6 22:42:22 2012 +0200

    Document the new error websocket-wss-needs-emacs-24

diff --git a/websocket.el b/websocket.el
index 1d9164c..e96a904 100644
--- a/websocket.el
+++ b/websocket.el
@@ -620,7 +620,12 @@ websocket processing, all of them having the 
error-condition
 `websocket-error' in addition to their own symbol:
 
 `websocket-unsupported-protocol': Data in the error signal is the
-protocol (such as \"wss\") that is unsupported.
+protocol that is unsupported.  For example, giving a URL starting
+with http by mistake raises this error.
+
+`websocket-wss-needs-emacs-24': Trying to connect wss protocol
+using Emacs < 24 raises this error.  You can catch this error
+also by `websocket-unsupported-protocol'.
 
 `websocket-received-error-http-response': Data in the error
 signal is the integer error number.

commit 99ab8c8ae50995afced95712e11bfa21ef02c71e
Author: Takafumi Arakaki <address@hidden>
Date:   Sat Oct 6 22:32:45 2012 +0200

    Add a new error websocket-wss-needs-emacs-24

diff --git a/websocket.el b/websocket.el
index 58238d0..1d9164c 100644
--- a/websocket.el
+++ b/websocket.el
@@ -371,6 +371,11 @@ the frame finishes.  If the frame is not completed, return 
NIL."
 (put 'websocket-unsupported-protocol 'error-conditions
      '(error websocket-error websocket-unsupported-protocol))
 (put 'websocket-unsupported-protocol 'error-message "Unsupported websocket 
protocol")
+(put 'websocket-wss-needs-emacs-24 'error-conditions
+     '(error websocket-error websocket-unsupported-protocol
+             websocket-wss-needs-emacs-24))
+(put 'websocket-wss-needs-emacs-24 'error-message
+     "wss protocol is not supported for Emacs before version 24.")
 (put 'websocket-received-error-http-response 'error-conditions
      '(error websocket-error websocket-received-error-http-response))
 (put 'websocket-received-error-http-response 'error-message
@@ -646,7 +651,7 @@ describing the problem with the frame.
                          (condition-case-no-debug nil
                              (open-network-stream name buf host port :type 
type :nowait nil)
                            (wrong-number-of-arguments
-                            (signal 'websocket-unsupported-protocol "wss")))))
+                            (signal 'websocket-wss-needs-emacs-24 "wss")))))
                  (signal 'websocket-unsupported-protocol (url-type 
url-struct))))
          (websocket (websocket-inner-create
                      :conn conn

commit 3c5871ba43930d0aef427559e643b8ba32aac043
Author: Takafumi Arakaki <address@hidden>
Date:   Sat Oct 6 22:27:57 2012 +0200

    Fix error message for websocket-unsupported-protocol

diff --git a/websocket.el b/websocket.el
index c340e63..58238d0 100644
--- a/websocket.el
+++ b/websocket.el
@@ -370,7 +370,7 @@ the frame finishes.  If the frame is not completed, return 
NIL."
 ;; Error symbols in use by the library
 (put 'websocket-unsupported-protocol 'error-conditions
      '(error websocket-error websocket-unsupported-protocol))
-(put 'websocket-unsupported-protocol 'error-message "Unsupport websocket 
protocol")
+(put 'websocket-unsupported-protocol 'error-message "Unsupported websocket 
protocol")
 (put 'websocket-received-error-http-response 'error-conditions
      '(error websocket-error websocket-received-error-http-response))
 (put 'websocket-received-error-http-response 'error-message

commit 379547c62aa3dfd2b20474a1a68f42d3df0bdd72
Author: Leo Liu <address@hidden>
Date:   Thu Oct 4 18:47:18 2012 +0800

    Release version 0.8

diff --git a/README.rst b/README.rst
index 8d07e85..f702340 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
 ==========================================
  Emacs Interface to command-line tool ack
 ==========================================
- 
+
 From http://betterthangrep.com/
 
     ack is a tool like grep, designed for programmers with large trees
@@ -10,6 +10,8 @@ From http://betterthangrep.com/
     ack is written purely in Perl, and takes advantage of the power of
     Perl's regular expressions.
 
+This package is part of `GNU ELPA <http://elpa.gnu.org>`_.
+
 Feature requests and bug reports are welcome. Thanks.
 
 Features
@@ -81,6 +83,11 @@ key bindings may be useful:
 - ``M-G`` => insert a template for ``git grep``, ``hg grep`` or ``bzr grep``
 - ``TAB`` => completion for ack options
 
+Bugs
+----
+
+https://github.com/leoliu/ack-el/issues
+
 Contributors
 ------------
 Phillip Lord
diff --git a/ack.el b/ack.el
index 80ed813..78bfd81 100644
--- a/ack.el
+++ b/ack.el
@@ -3,9 +3,10 @@
 ;; Copyright (C) 2012  Leo Liu
 
 ;; Author: Leo Liu <address@hidden>
+;; Version: 0.8
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
-;; Version: 0.7
+;; URL: https://github.com/leoliu/ack-el
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index 64ddff4..dfac435 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -5,6 +5,7 @@
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-09-26
+;; URL: https://github.com/leoliu/ack-el
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by

commit 1be7648c0248bb95505c2c26b1bef70c2cf38ebe
Author: Leo Liu <address@hidden>
Date:   Thu Oct 4 18:20:25 2012 +0800

    Add 'bzr grep' to ack-vc-grep-commands

diff --git a/README.rst b/README.rst
index 882ee8c..8d07e85 100644
--- a/README.rst
+++ b/README.rst
@@ -18,7 +18,7 @@ Features
 - Neither ``--nogroup`` nor ``--noheading`` is required
 - Handle colors using the standard library ``ansi-color.el``
 - Completion for ack options while reading from the minibuffer
-- Support ``git grep`` and ``hg grep``
+- Support ``git grep``, ``hg grep`` and ``bzr grep``
 - Support both emacs 23 and 24
 
 Screenshots
@@ -78,7 +78,7 @@ While reading ack command and args from the minibuffer, the 
following
 key bindings may be useful:
 
 - ``M-I`` => insert a template for case-insensitive file name search
-- ``M-G`` => insert a template for ``git grep`` or ``hg grep``
+- ``M-G`` => insert a template for ``git grep``, ``hg grep`` or ``bzr grep``
 - ``TAB`` => completion for ack options
 
 Contributors
diff --git a/ack.el b/ack.el
index e5b6e5c..80ed813 100644
--- a/ack.el
+++ b/ack.el
@@ -57,9 +57,10 @@ environment variable and ~/.ackrc, which you can disable by 
the
   :group 'ack)
 
 (defcustom ack-vc-grep-commands
-  '((".git" . "git --no-pager grep -i -n --color")
-    ;; (".bzr" . "bzr grep")
-    (".hg" . "hg grep -i -n"))
+  '((".git" . "git --no-pager grep --color -n -i")
+    (".hg" . "hg grep -n -i")
+    ;; Plugin bzr-grep required for bzr < 2.6
+    (".bzr" . "bzr grep --color=always -n -i"))
   "An alist of vc grep commands for `ack-skel-vc-grep'.
 Each element is of the form (VC_DIR . CMD)."
   :type '(repeat (cons string string))
@@ -225,6 +226,7 @@ This gets tacked on the end of the generated expressions.")
 (defvar ack-process-setup-function 'ack-process-setup)
 
 (defun ack-process-setup ()
+  ;; Handle `hg grep' output
   (when (string-match-p "^[ \t]*hg[ \t]" (car compilation-arguments))
     (setq compilation-error-regexp-alist
           '(("^\\(.+?:[0-9]+:\\)\\(?:\\([0-9]+\\):\\)?" 1 2)))
@@ -236,6 +238,16 @@ This gets tacked on the end of the generated expressions.")
             (save-match-data
               (if (string-match "\\(.+\\):\\([0-9]+\\):" file)
                   (match-string 1 file)
+                file)))))
+  ;; Handle `bzr grep' output
+  (when (string-match-p "^[ \t]*bzr[ \t]" (car compilation-arguments))
+    (make-local-variable 'compilation-parse-errors-filename-function)
+    (setq compilation-parse-errors-filename-function
+          (lambda (file)
+            (save-match-data
+              ;; 'bzr grep -r' has files like `termcolor.py~147'
+              (if (string-match "\\(.+\\)~\\([0-9]+\\)" file)
+                  (match-string 1 file)
                 file))))))
 
 (define-compilation-mode ack-mode "Ack"

commit 88ada6dc4f6228bdd03ebc4eb0675ab54d79d387
Author: Leo Liu <address@hidden>
Date:   Thu Oct 4 14:48:06 2012 +0800

    New user variable ack-default-directory-function
    
    to decide default directory to run `ack'.
    Rename ack-project-pattern-list to ack-project-root-patterns.

diff --git a/ack.el b/ack.el
index 4884e9f..e5b6e5c 100644
--- a/ack.el
+++ b/ack.el
@@ -37,26 +37,6 @@
   :group 'tools
   :group 'processes)
 
-(defcustom ack-project-pattern-list
-  (list (concat "\\`" (regexp-quote dir-locals-file) "\\'")
-        "\\`Project\\.ede\\'"
-        "\\.xcodeproj\\'"         ; xcode
-        "\\`\\.ropeproject\\'"    ; python rope
-        ;; ".git" ".svn" ".hg" ".bzr" ".CVS"
-        "\\`\\.\\(?:CVS\\|bzr\\|git\\|hg\\|svn\\)\\'")
-  "A list of regexps that match files in a project root."
-  :type '(repeat string)
-  :group 'ack)
-
-(defcustom ack-vc-grep-commands
-  '((".git" . "git --no-pager grep -i -n --color")
-    ;; (".bzr" . "bzr grep")
-    (".hg" . "hg grep -i -n"))
-  "An alist of vc grep commands for `ack-skel-vc-grep'.
-Each element is of the form (VC_DIR . CMD)."
-  :type '(repeat (cons string string))
-  :group 'ack)
-
 ;; Used implicitly by `define-compilation-mode'
 (defcustom ack-scroll-output nil
   "Similar to `compilation-scroll-output' but for the *Ack* buffer."
@@ -76,6 +56,32 @@ environment variable and ~/.ackrc, which you can disable by 
the
   :type 'string
   :group 'ack)
 
+(defcustom ack-vc-grep-commands
+  '((".git" . "git --no-pager grep -i -n --color")
+    ;; (".bzr" . "bzr grep")
+    (".hg" . "hg grep -i -n"))
+  "An alist of vc grep commands for `ack-skel-vc-grep'.
+Each element is of the form (VC_DIR . CMD)."
+  :type '(repeat (cons string string))
+  :group 'ack)
+
+(defcustom ack-default-directory-function 'ack-default-directory
+  "A function to return the default directory for `ack'.
+It is called with one arg, the prefix arg to `ack'."
+  :type 'function
+  :group 'ack)
+
+(defcustom ack-project-root-patterns
+  (list (concat "\\`" (regexp-quote dir-locals-file) "\\'")
+        "\\`Project\\.ede\\'"
+        "\\.xcodeproj\\'"               ; xcode
+        "\\`\\.ropeproject\\'"          ; python rope
+        "\\`\\.\\(?:CVS\\|bzr\\|git\\|hg\\|svn\\)\\'")
+  "A list of regexps to match files in a project root.
+Used by `ack-guess-project-root'."
+  :type '(repeat string)
+  :group 'ack)
+
 ;;; ======== END of USER OPTIONS ========
 
 (defvar ack-history nil "History list for ack.")
@@ -249,7 +255,7 @@ This gets tacked on the end of the generated expressions.")
               nil))))))
 
 (defun ack-skel-file ()
-  "Insert a template for case-insensitive filename search."
+  "Insert a template for case-insensitive file name search."
   (interactive)
   (delete-minibuffer-contents)
   (let ((ack (or (car (split-string ack-command nil t)) "ack")))
@@ -287,7 +293,7 @@ This gets tacked on the end of the generated expressions.")
 
 (defun ack-guess-project-root (start-directory &optional regexp)
   (let ((regexp (or regexp
-                    (mapconcat 'identity ack-project-pattern-list "\\|")))
+                    (mapconcat 'identity ack-project-root-patterns "\\|")))
         (parent (file-name-directory
                  (directory-file-name (expand-file-name start-directory)))))
     (if (directory-files start-directory nil regexp)
@@ -295,18 +301,32 @@ This gets tacked on the end of the generated 
expressions.")
       (unless (equal parent start-directory)
         (ack-guess-project-root parent regexp)))))
 
+(defun ack-default-directory (arg)
+  "A function for `ack-default-directory-function'.
+With no \\[universal-argument], return `default-directory';
+With one \\[universal-argument], find the project root according to
+`ack-project-root-patterns';
+Otherwise, interactively choose a directory."
+  (cond
+   ((not arg) default-directory)
+   ((= (prefix-numeric-value arg) 4)
+    (or (ack-guess-project-root default-directory)
+        (ack-default-directory '(16))))
+   (t (read-directory-name "In directory: " nil nil t))))
+
 ;;;###autoload
 (defun ack (command-args &optional directory)
   "Run ack using COMMAND-ARGS and collect output in a buffer.
-With prefix, ask for the DIRECTORY to run ack; otherwise the
-current project root is used.
+When called interactively, the value of DIRECTORY is provided by
+`ack-default-directory-function'.
 
 The following keys are available while reading from the
 minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (let ((project-root)
+   (let ((project-root (funcall ack-default-directory-function
+                                current-prefix-arg))
          ;; Disable completion cycling; see http://debbugs.gnu.org/12221
          (completion-cycle-threshold nil))
      (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
@@ -315,10 +335,7 @@ minibuffer:
              (read-from-minibuffer "Run ack (like this): "
                                    ack-command ack-minibuffer-local-map
                                    nil 'ack-history))
-           (if current-prefix-arg
-               (read-directory-name "In directory: " nil nil t)
-             (or project-root
-                 (ack-guess-project-root default-directory))))))
+           project-root)))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))
     (compilation-start command-args 'ack-mode)))

commit a2e8934cfadb242af6df209703311b062d72d448
Author: Leo Liu <address@hidden>
Date:   Wed Oct 3 23:37:46 2012 +0800

    Work around bug http://debbugs.gnu.org/12221

diff --git a/ack.el b/ack.el
index 820b842..4884e9f 100644
--- a/ack.el
+++ b/ack.el
@@ -306,7 +306,9 @@ minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (let ((project-root))
+   (let ((project-root)
+         ;; Disable completion cycling; see http://debbugs.gnu.org/12221
+         (completion-cycle-threshold nil))
      (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
                                            'shell-completion-vars
                                          'pcomplete-shell-setup)

commit 6b3f092e023313c5a00c5cb1796b4ba78039e779
Author: Dmitry Gutov <address@hidden>
Date:   Wed Oct 3 05:31:10 2012 +0400

    Show keybindings in the mode description
    
    Close #71

diff --git a/js2-mode.el b/js2-mode.el
index 0281531..1ba5318 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2105,17 +2105,17 @@ modifications to the buffer."
   (declare (indent 0) (debug t))
   (let ((modified (make-symbol "modified")))
     `(let ((,modified (buffer-modified-p))
-          (inhibit-read-only t)
-          (inhibit-modification-hooks t)
-          (buffer-undo-list t)
-          (deactivate-mark nil)
-          ;; Apparently these avoid file locking problems.
-          (buffer-file-name nil)
-          (buffer-file-truename nil))
+           (inhibit-read-only t)
+           (inhibit-modification-hooks t)
+           (buffer-undo-list t)
+           (deactivate-mark nil)
+           ;; Apparently these avoid file locking problems.
+           (buffer-file-name nil)
+           (buffer-file-truename nil))
        (unwind-protect
-          (progn ,@body)
-        (unless ,modified
-          (restore-buffer-modified-p nil))))))
+           (progn ,@body)
+         (unless ,modified
+           (restore-buffer-modified-p nil))))))
 
 (defmacro js2-with-underscore-as-word-syntax (&rest body)
   "Evaluate BODY with the _ character set to be word-syntax."
@@ -9945,20 +9945,20 @@ indented to the same column as the current line."
   (save-excursion
     (save-match-data
       (when (looking-at "\\s-*\\<while\\>")
-       (if (save-excursion
-             (skip-chars-backward "[ \t\n]*}")
-             (looking-at "[ \t\n]*}"))
-           (save-excursion
-             (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
-         (js2-re-search-backward "\\<do\\>" (point-at-bol) t)
-         (or (looking-at "\\<do\\>")
-             (let ((saved-indent (current-indentation)))
-               (while (and (js2-re-search-backward "^[ \t]*\\<" nil t)
-                           (/= (current-indentation) saved-indent)))
-               (and (looking-at "[ \t]*\\<do\\>")
-                    (not (js2-re-search-forward
-                          "\\<while\\>" (point-at-eol) t))
-                    (= (current-indentation) saved-indent)))))))))
+        (if (save-excursion
+              (skip-chars-backward "[ \t\n]*}")
+              (looking-at "[ \t\n]*}"))
+            (save-excursion
+              (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
+          (js2-re-search-backward "\\<do\\>" (point-at-bol) t)
+          (or (looking-at "\\<do\\>")
+              (let ((saved-indent (current-indentation)))
+                (while (and (js2-re-search-backward "^[ \t]*\\<" nil t)
+                            (/= (current-indentation) saved-indent)))
+                (and (looking-at "[ \t]*\\<do\\>")
+                     (not (js2-re-search-forward
+                           "\\<while\\>" (point-at-eol) t))
+                     (= (current-indentation) saved-indent)))))))))
 
 (defun js2-multiline-decl-indentation ()
   "Returns the declaration indentation column if the current line belongs
@@ -10430,7 +10430,9 @@ If so, we don't ever want to use bounce-indent."
 
 ;;;###autoload
 (defun js2-mode ()
-  "Major mode for editing JavaScript code."
+  "Major mode for editing JavaScript code.
+
+\\{js2-mode-map}"
   (interactive)
   (kill-all-local-variables)
   (set-syntax-table js2-mode-syntax-table)

commit 389992b77b25bfd1cb7e4492965ed8a5f1ff852d
Author: Leo Liu <address@hidden>
Date:   Tue Oct 2 17:41:32 2012 +0800

    Parse ack options on the fly
    
    to support both ack 1.x and 2.x options.

diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index ace80d2..64ddff4 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -30,80 +30,21 @@
 ;; Usage:
 ;;   - To complete short options type '-' first
 ;;   - To complete long options type '--' first
-;;   - Color name completion is also supported following
-;;       --color-filename=, --color-match= and --color-lineno=.
+;;   - Color name completion is supported following
+;;       --color-filename=, --color-match= and --color-lineno=
+;;   - Type completion is supported following --type=
 
 ;;; Code:
 
 (require 'pcomplete)
 
-(defvar pcmpl-ack-short-options
-  (mapconcat (lambda (o) (substring o 1))
-             '("-a" "-A" "-B" "-C" "-c" "-f" "-G" "-g"
-               "-H" "-h" "-i" "-l" "-L" "-m" "-n"
-               "-o" "-Q" "-r" "-R"
-               "-u" "-v" "-w" "-1")
-             "")
-  "Short options for the `ack' command.")
-
-(defvar pcmpl-ack-long-options
-  '("--after-context="
-    "--all-types"
-    "--before-context="
-    "--break"
-    "--nobreak"
-    "--color"
-    "--nocolor"
-    "--colour"
-    "--nocolour"
-    "--color-filename="
-    "--color-match="
-    "--color-lineno="
-    "--column"
-    "--context="
-    "--count"
-    "--env"
-    "--noenv"
-    "--files-with-matches"
-    "--files-without-matches"
-    "--flush"
-    "--follow"
-    "--nofollow"
-    "--group"
-    "--nogroup"
-    "--heading"
-    "--noheading"
-    "--ignore-case"
-    "--ignore-dir="
-    "--noignore-dir="
-    "--invert-match"
-    "--line="
-    "--literal"
-    "--match"
-    "--max-count="
-    "--no-filename"
-    "--output="
-    "--pager="
-    "--nopager"
-    "--passthru"
-    "--print0"
-    "--recurse"
-    "--norecurse"
-    "--smart-case"
-    "--nosmart-case"
-    "--sort-files"
-    "--type="
-    "--type-add"
-    "--type-set"
-    "--unrestricted"
-    "--with-filename"
-    "--word-regexp"
-    "--help"
-    "--help-types"
-    "--man"
-    "--thpppt"
-    "--version")
-  "Long options for the `ack' command.")
+(defcustom pcmpl-ack-program
+  (file-name-nondirectory (or (executable-find "ack-grep")
+                              (executable-find "ack")
+                              "ack"))
+  "Name of the ack program."
+  :type 'file
+  :group 'pcomplete)
 
 (defvar pcmpl-ack-color-options
   '("clear"
@@ -131,13 +72,47 @@
     "on_white")
   "Color names for the `ack' command.")
 
+(defun pcmpl-ack-run (buffer &rest args)
+  "Run ack with ARGS and send the output to BUFFER."
+  (condition-case nil
+      (apply 'call-process (or pcmpl-ack-program "ack") nil buffer nil args)
+    (file-error -1)))
+
+(defun pcmpl-ack-short-options ()
+  "Short options for the `ack' command."
+  (with-temp-buffer
+    (let (options)
+      (when (zerop (pcmpl-ack-run t "--help"))
+        (goto-char (point-min))
+        (while (re-search-forward "^  -\\([^-]\\)" nil t)
+          (push (match-string 1) options))
+        (mapconcat 'identity (nreverse options) "")))))
+
+(defun pcmpl-ack-long-options (&optional arg)
+  "Long options for the `ack' command."
+  (with-temp-buffer
+    (let (options)
+      (when (zerop (pcmpl-ack-run t (or arg "--help")))
+        (goto-char (point-min))
+        (while (re-search-forward
+                "\\(?:   ?\\|, \\)\\(--\\(\\[no\\]\\)?\\([[:alnum:]-]+=?\\)\\)"
+                nil t)
+          (if (not (match-string 2))
+              (push (match-string 1) options)
+            (push (concat "--" (match-string 3)) options)
+            (push (concat "--no" (match-string 3)) options)))
+        (nreverse options)))))
+
+(defun pcmpl-ack-type-options ()
+  "A list of types for the `ack' command."
+  (pcmpl-ack-long-options "--help-types"))
+
 ;;;###autoload
 (defun pcomplete/ack ()
   "Completion for the `ack' command.
 Start an argument with '-' to complete short options and '--' for
 long options."
   ;; No space after =
-  (add-to-list 'pcomplete-suffix-list ?=)
   (while t
     (if (pcomplete-match "^-" 0)
         (cond
@@ -147,9 +122,15 @@ long options."
          ((pcomplete-match "^--\\(?:no\\)?ignore-dir=\\(\\S-*\\)" 0)
           (pcomplete-here* (pcomplete-dirs)
                            (pcomplete-match-string 1 0) t))
+         ((pcomplete-match "^--type=\\(\\S-*\\)" 0)
+          (pcomplete-here* (mapcar (lambda (type-option)
+                                     (substring type-option 2))
+                                   (pcmpl-ack-type-options))
+                           (pcomplete-match-string 1 0) t))
          ((pcomplete-match "^--" 0)
-          (pcomplete-here* pcmpl-ack-long-options))
-         (t (pcomplete-opt pcmpl-ack-short-options)))
+          (pcomplete-here* (append (pcmpl-ack-long-options)
+                                   (pcmpl-ack-type-options))))
+         (t (pcomplete-opt (pcmpl-ack-short-options))))
       (pcomplete-here* (pcomplete-dirs-or-entries)))))
 
 ;;;###autoload

commit fa107c54964494dbe5c4b0e850c34c0350a4160a
Author: Leo Liu <address@hidden>
Date:   Tue Oct 2 17:22:26 2012 +0800

    Document last change

diff --git a/README.rst b/README.rst
index 24d0413..882ee8c 100644
--- a/README.rst
+++ b/README.rst
@@ -18,11 +18,19 @@ Features
 - Neither ``--nogroup`` nor ``--noheading`` is required
 - Handle colors using the standard library ``ansi-color.el``
 - Completion for ack options while reading from the minibuffer
+- Support ``git grep`` and ``hg grep``
 - Support both emacs 23 and 24
 
 Screenshots
 -----------
 
+.. figure:: http://i.imgur.com/mrk8k.png
+   :width: 400 px
+   :target: http://i.imgur.com/mrk8k.png
+   :alt: ack-git-grep.png
+
+   ``git --no-pager grep -n --color 'hg grep'``
+
 .. figure:: http://i.imgur.com/a72Ap.png
    :width: 400 px
    :target: http://i.imgur.com/a72Ap.png
@@ -48,8 +56,8 @@ or::
 
  (autoload 'ack "ack" nil t)
 
-Completion
-~~~~~~~~~~
+Completion (optional)
+~~~~~~~~~~~~~~~~~~~~~
 
 Place ``pcmpl-ack.el`` in the ``load-path`` and add::
 
@@ -70,6 +78,7 @@ While reading ack command and args from the minibuffer, the 
following
 key bindings may be useful:
 
 - ``M-I`` => insert a template for case-insensitive file name search
+- ``M-G`` => insert a template for ``git grep`` or ``hg grep``
 - ``TAB`` => completion for ack options
 
 Contributors

commit f0392a63145a1935e97092100af687482e64aaa9
Author: Leo Liu <address@hidden>
Date:   Mon Oct 1 00:02:24 2012 +0800

    Bind new template command ack-skel-vc-grep to M-G

diff --git a/ack.el b/ack.el
index cddb006..820b842 100644
--- a/ack.el
+++ b/ack.el
@@ -48,6 +48,15 @@
   :type '(repeat string)
   :group 'ack)
 
+(defcustom ack-vc-grep-commands
+  '((".git" . "git --no-pager grep -i -n --color")
+    ;; (".bzr" . "bzr grep")
+    (".hg" . "hg grep -i -n"))
+  "An alist of vc grep commands for `ack-skel-vc-grep'.
+Each element is of the form (VC_DIR . CMD)."
+  :type '(repeat (cons string string))
+  :group 'ack)
+
 ;; Used implicitly by `define-compilation-mode'
 (defcustom ack-scroll-output nil
   "Similar to `compilation-scroll-output' but for the *Ack* buffer."
@@ -207,6 +216,22 @@ This gets tacked on the end of the generated expressions.")
 
 (defvar ack--ansi-color-last-marker)
 
+(defvar ack-process-setup-function 'ack-process-setup)
+
+(defun ack-process-setup ()
+  (when (string-match-p "^[ \t]*hg[ \t]" (car compilation-arguments))
+    (setq compilation-error-regexp-alist
+          '(("^\\(.+?:[0-9]+:\\)\\(?:\\([0-9]+\\):\\)?" 1 2)))
+    (when (< emacs-major-version 24)
+      (setq font-lock-keywords (compilation-mode-font-lock-keywords)))
+    (make-local-variable 'compilation-parse-errors-filename-function)
+    (setq compilation-parse-errors-filename-function
+          (lambda (file)
+            (save-match-data
+              (if (string-match "\\(.+\\):\\([0-9]+\\):" file)
+                  (match-string 1 file)
+                file))))))
+
 (define-compilation-mode ack-mode "Ack"
   "A compilation mode tailored for ack."
   (set (make-local-variable 'compilation-disable-input) t)
@@ -230,6 +255,24 @@ This gets tacked on the end of the generated expressions.")
   (let ((ack (or (car (split-string ack-command nil t)) "ack")))
     (skeleton-insert '(nil ack " -g '(?i:" _ ")'"))))
 
+(defvar project-root)                   ; dynamically bound in `ack'
+
+(defun ack-skel-vc-grep ()
+  "Insert a template for vc grep search."
+  (interactive)
+  (let* ((regexp (concat "\\`" (regexp-opt
+                                (mapcar 'car ack-vc-grep-commands))
+                         "\\'"))
+         (root (or (ack-guess-project-root default-directory regexp)
+                   (error "Cannot locate vc project root")))
+         (which (car (directory-files root nil regexp)))
+         (cmd (or (cdr (assoc which ack-vc-grep-commands))
+                  (error "No command provided for `%s grep'"
+                         (substring which 1)))))
+    (setq project-root root)
+    (delete-minibuffer-contents)
+    (skeleton-insert '(nil cmd " '" _ "'"))))
+
 (defvar ack-minibuffer-local-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
@@ -237,6 +280,7 @@ This gets tacked on the end of the generated expressions.")
                              'completion-at-point
                            'pcomplete))
     (define-key map "\M-I" 'ack-skel-file)
+    (define-key map "\M-G" 'ack-skel-vc-grep)
     (define-key map "'" 'skeleton-pair-insert-maybe)
     map)
   "Keymap used for reading `ack' command and args in minibuffer.")
@@ -262,15 +306,17 @@ minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
-                                         'shell-completion-vars
-                                       'pcomplete-shell-setup)
-           (read-from-minibuffer "Run ack (like this): "
-                                 ack-command ack-minibuffer-local-map
-                                 nil 'ack-history))
-         (if current-prefix-arg
-             (read-directory-name "In directory: " nil nil t)
-           (ack-guess-project-root default-directory))))
+   (let ((project-root))
+     (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
+                                           'shell-completion-vars
+                                         'pcomplete-shell-setup)
+             (read-from-minibuffer "Run ack (like this): "
+                                   ack-command ack-minibuffer-local-map
+                                   nil 'ack-history))
+           (if current-prefix-arg
+               (read-directory-name "In directory: " nil nil t)
+             (or project-root
+                 (ack-guess-project-root default-directory))))))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))
     (compilation-start command-args 'ack-mode)))

commit aefe34a40d41b3ec57c86e552b0c3e9f29cbdcad
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 18:09:32 2012 +0800

    Release version 0.7

diff --git a/README.rst b/README.rst
index 5178186..24d0413 100644
--- a/README.rst
+++ b/README.rst
@@ -12,6 +12,31 @@ From http://betterthangrep.com/
 
 Feature requests and bug reports are welcome. Thanks.
 
+Features
+--------
+
+- Neither ``--nogroup`` nor ``--noheading`` is required
+- Handle colors using the standard library ``ansi-color.el``
+- Completion for ack options while reading from the minibuffer
+- Support both emacs 23 and 24
+
+Screenshots
+-----------
+
+.. figure:: http://i.imgur.com/a72Ap.png
+   :width: 400 px
+   :target: http://i.imgur.com/a72Ap.png
+   :alt: ack-emacs23-1.png
+
+   ``ack --column 'ack is.*tool'``
+
+.. figure:: http://i.imgur.com/U2vFz.png
+   :width: 400 px
+   :target: http://i.imgur.com/U2vFz.png
+   :alt: ack-emacs23-2.png
+
+   ``ack --column --nogroup --nocolor 'ack is.*tool'``
+
 Install
 -------
 
@@ -37,15 +62,15 @@ options while ``M-x ack`` or in shell/eshell.
 Usage
 -----
 
-#. ``M-x ack`` and provide a pattern to search.
-#. ``C-u M-x ack`` like ``M-x ack`` but allow you to select a
-   directory to search.
+- ``M-x ack`` and provide a pattern to search.
+- ``C-u M-x ack`` like ``M-x ack`` but allow you to select a
+  directory to search.
 
 While reading ack command and args from the minibuffer, the following
 key bindings may be useful:
 
-#. ``M-I`` => insert a template for case-insensitive file name search
-#. ``TAB`` => completion for ack options
+- ``M-I`` => insert a template for case-insensitive file name search
+- ``TAB`` => completion for ack options
 
 Contributors
 ------------
diff --git a/ack.el b/ack.el
index 200505f..cddb006 100644
--- a/ack.el
+++ b/ack.el
@@ -5,7 +5,7 @@
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
-;; Version: 0.6
+;; Version: 0.7
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -71,14 +71,12 @@ environment variable and ~/.ackrc, which you can disable by 
the
 
 (defvar ack-history nil "History list for ack.")
 
-;; Used implicitly by `define-compilation-mode'
 (defvar ack-first-column 0
   "Value to use for `compilation-first-column' in ack buffers.")
 
 (defvar ack-error-screen-columns nil
   "Value to use for `compilation-error-screen-columns' in ack buffers.")
 
-;; Used implicitly by `define-compilation-mode'
 (defvar ack-error "ack match"
   "Stem of message to print when no matches are found.")
 
@@ -93,7 +91,6 @@ This function is called from `compilation-filter-hook'."
                (put-text-property beg end 'ack-color t)))))
       (ansi-color-apply-on-region compilation-filter-start (point)))))
 
-;; Used implicitly by `define-compilation-mode'
 (defvar ack-mode-font-lock-keywords
   '(("^--$" 0 'shadow)
     ;; Command output lines.

commit 38e5c5efbdcb7606da9aa854e1603323095f5db1
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 17:49:53 2012 +0800

    Handle the output of 'ack --group --column' for emacs-23

diff --git a/ack.el b/ack.el
index 5ca50d8..200505f 100644
--- a/ack.el
+++ b/ack.el
@@ -151,6 +151,35 @@ This gets tacked on the end of the generated expressions.")
                        (min (1+ (line-end-position)) (point-max)) 'ack-file 
file)
     (list file)))
 
+;;; For emacs < 24
+(when (< emacs-major-version 24)
+  (defun ack--line (file col)
+    (if (string-match-p "\\`[1-9][0-9]*\\'" (car file))
+        (let ((has-ansi-color (overlays-at (match-beginning 1))))
+          ;; See `compilation-mode-font-lock-keywords' where there is
+          ;; overriding font-locking of FILE. Thus use the display
+          ;; property here to avoid being overridden.
+          (put-text-property
+           (match-beginning 1) (match-end 1)
+           'display
+           (propertize (match-string-no-properties 1)
+                       'face (list (and (not has-ansi-color)
+                                        compilation-line-face)
+                                   :weight 'normal :inherit 'underline)))
+          (list nil (ack--file)
+                (string-to-number (match-string 1))
+                (1- (string-to-number (match-string 3)))))
+      (put-text-property (match-beginning 3)
+                         (match-end 3)
+                         'font-lock-face compilation-line-face)
+      (list nil file
+            (string-to-number (match-string 3))
+            (when (match-string 4)
+              (put-text-property (match-beginning 4)
+                                 (match-end 4)
+                                 'font-lock-face compilation-column-face)
+              (1- (string-to-number (match-string 4))))))))
+
 ;;; In emacs-24 and above, `compilation-mode-font-lock-keywords' ->
 ;;; `compilation--ensure-parse' -> `compilation--parse-region' ->
 ;;; `compilation-parse-errors' -> `compilation-error-properties'.
@@ -161,19 +190,21 @@ This gets tacked on the end of the generated 
expressions.")
 ;;; after some transformation, so later entries can override earlier
 ;;; entries.
 ;;;
-;;; The output of 'ack --nocolor --group --column WHATEVER' matches
-;;; both regexps in `ack-regexp-alist' and this fails emacs-23 in
-;;; finding the right file.
+;;; The output of 'ack --group --column WHATEVER' matches both regexps
+;;; in `ack-regexp-alist' and this fails emacs-23 in finding the right
+;;; file. So ack--line is used to disambiguate this case.
 
 (defconst ack-error-regexp-alist
-  '(;; grouping line (--group or --heading)
+  `(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      ack--file 1 (ack--column-start . ack--column-end)
      nil nil (4 compilation-column-face nil t))
     ;; none grouping line (--nogroup or --noheading)
     
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     1 3 (ack--column-start . ack--column-end)
-     nil nil (4 compilation-column-face nil t))
+     ,@(if (>= emacs-major-version 24)
+           '(1 3 (ack--column-start . ack--column-end)
+               nil nil (4 compilation-column-face nil t))
+         '(1 ack--line 4)))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit 86e1a266379d22948aa24502aa744e6b4762c4ef
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 11:40:37 2012 +0800

    Fix ack-mode-font-lock-keywords for emacs-23

diff --git a/ack.el b/ack.el
index 97b3fdd..5ca50d8 100644
--- a/ack.el
+++ b/ack.el
@@ -99,11 +99,11 @@ This function is called from `compilation-filter-hook'."
     ;; Command output lines.
     (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or 
directory\\|device or address\\)\\)$"
      1 'compilation-error)
-    ;; remove match from ack-regexp-alist before fontifying
-    ("^Ack \\(?:started\\|finished at\\).*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
+    ;; Remove match from ack-error-regexp-alist before fontifying
+    ("^Ack \\(?:started\\|finished\\) at.*"
+     (0 '(face nil compilation-message nil message nil help-echo nil 
mouse-face nil) t))
     ("^Ack \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
-     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
+     (0 '(face nil compilation-message nil message nil help-echo nil 
mouse-face nil) t)
      (1 'compilation-error)
      (2 'compilation-error nil t)))
   "Additional things to highlight in ack output.

commit 7a0ae5bc110f1082dcc24f63aa0feae9d420a65a
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 02:23:44 2012 +0800

    Rename ack-regexp-alist to ack-error-regexp-alist

diff --git a/ack.el b/ack.el
index c9f1372..97b3fdd 100644
--- a/ack.el
+++ b/ack.el
@@ -165,7 +165,7 @@ This gets tacked on the end of the generated expressions.")
 ;;; both regexps in `ack-regexp-alist' and this fails emacs-23 in
 ;;; finding the right file.
 
-(defconst ack-regexp-alist
+(defconst ack-error-regexp-alist
   '(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      ack--file 1 (ack--column-start . ack--column-end)
@@ -184,8 +184,6 @@ This gets tacked on the end of the generated expressions.")
   (set (make-local-variable 'compilation-disable-input) t)
   (set (make-local-variable 'compilation-error-face)
        'compilation-info)
-  (set (make-local-variable 'compilation-error-regexp-alist)
-       ack-regexp-alist)
   (if (>= emacs-major-version 24)
       (add-hook 'compilation-filter-hook 'ack-filter nil t)
     (set (make-local-variable 'ack--ansi-color-last-marker)

commit 1237b491508e17f120b2bf72ceb7e08e772dc201
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 02:21:17 2012 +0800

    Better handling of column number highlighting

diff --git a/ack.el b/ack.el
index b457f86..c9f1372 100644
--- a/ack.el
+++ b/ack.el
@@ -122,9 +122,6 @@ This gets tacked on the end of the generated expressions.")
         (when mbeg (- mbeg beg)))
       ;; Use column number from `ack' itself if available
       (when (match-string 4)
-        (put-text-property (match-beginning 4)
-                           (match-end 4)
-                           'font-lock-face compilation-column-face)
         (1- (string-to-number (match-string 4))))))
 
 (defun ack--column-end ()
@@ -171,10 +168,12 @@ This gets tacked on the end of the generated 
expressions.")
 (defconst ack-regexp-alist
   '(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     ack--file 1 (ack--column-start . ack--column-end))
+     ack--file 1 (ack--column-start . ack--column-end)
+     nil nil (4 compilation-column-face nil t))
     ;; none grouping line (--nogroup or --noheading)
     
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     1 3 (ack--column-start . ack--column-end))
+     1 3 (ack--column-start . ack--column-end)
+     nil nil (4 compilation-column-face nil t))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit ae1fdace89cf97de3bcafe044b8724c9c4d76028
Author: Leo Liu <address@hidden>
Date:   Sun Sep 30 02:00:23 2012 +0800

    Loose the requirement of --nocolor in emacs 23

diff --git a/ack.el b/ack.el
index 24c8775..b457f86 100644
--- a/ack.el
+++ b/ack.el
@@ -28,8 +28,8 @@
 ;;; Code:
 
 (require 'compile)
+(require 'ansi-color)
 (when (>= emacs-major-version 24)
-  (require 'ansi-color)
   (autoload 'shell-completion-vars "shell"))
 
 (defgroup ack nil
@@ -56,12 +56,9 @@
 
 (defcustom ack-command
   ;; Note: on GNU/Linux ack may be renamed to ack-grep
-  (let ((ack (or (executable-find "ack-grep")
-                 (executable-find "ack")
-                 "ack"))
-        (args (when (< emacs-major-version 24)
-                "--nocolor ")))
-    (concat (file-name-nondirectory ack) " " args))
+  (concat (file-name-nondirectory (or (executable-find "ack-grep")
+                                      (executable-find "ack")
+                                      "ack")) " ")
   "The default ack command for \\[ack].
 
 Note also options to ack can be specified in ACK_OPTIONS
@@ -181,6 +178,8 @@ This gets tacked on the end of the generated expressions.")
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 
+(defvar ack--ansi-color-last-marker)
+
 (define-compilation-mode ack-mode "Ack"
   "A compilation mode tailored for ack."
   (set (make-local-variable 'compilation-disable-input) t)
@@ -188,8 +187,16 @@ This gets tacked on the end of the generated expressions.")
        'compilation-info)
   (set (make-local-variable 'compilation-error-regexp-alist)
        ack-regexp-alist)
-  (when (boundp 'compilation-filter-hook)
-    (add-hook 'compilation-filter-hook 'ack-filter nil t)))
+  (if (>= emacs-major-version 24)
+      (add-hook 'compilation-filter-hook 'ack-filter nil t)
+    (set (make-local-variable 'ack--ansi-color-last-marker)
+         (point-min-marker))
+    (font-lock-add-keywords
+     nil '(((lambda (limit)
+              (let ((beg (marker-position ack--ansi-color-last-marker)))
+                (move-marker ack--ansi-color-last-marker limit)
+                (ansi-color-apply-on-region beg ack--ansi-color-last-marker))
+              nil))))))
 
 (defun ack-skel-file ()
   "Insert a template for case-insensitive filename search."

commit 511dd418fb002dfb636ebf9e0b05fce4c903ae34
Author: Leo Liu <address@hidden>
Date:   Sat Sep 29 15:54:55 2012 +0800

    Document problematic ack-regexp-alist for emacs-23

diff --git a/ack.el b/ack.el
index 61f7f29..24c8775 100644
--- a/ack.el
+++ b/ack.el
@@ -157,6 +157,20 @@ This gets tacked on the end of the generated expressions.")
                        (min (1+ (line-end-position)) (point-max)) 'ack-file 
file)
     (list file)))
 
+;;; In emacs-24 and above, `compilation-mode-font-lock-keywords' ->
+;;; `compilation--ensure-parse' -> `compilation--parse-region' ->
+;;; `compilation-parse-errors' -> `compilation-error-properties'.
+;;; `compilation-error-properties' returns nil if a previous pattern
+;;; in the regexp alist has already been applied in a region.
+;;;
+;;; In emacs-23, `ack-regexp-alist' is a part of `font-lock-keywords'
+;;; after some transformation, so later entries can override earlier
+;;; entries.
+;;;
+;;; The output of 'ack --nocolor --group --column WHATEVER' matches
+;;; both regexps in `ack-regexp-alist' and this fails emacs-23 in
+;;; finding the right file.
+
 (defconst ack-regexp-alist
   '(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"

commit be3031f0473ff47ed045e81c141b977af937b740
Author: Leo Liu <address@hidden>
Date:   Sat Sep 29 12:00:17 2012 +0800

    Revert "Fix ack-regexp-alist for emacs-23"
    
    This reverts commit 037cdcc2239a7bdf3b8ce61b7d8813eeba6fc856.

diff --git a/ack.el b/ack.el
index d9db9ba..61f7f29 100644
--- a/ack.el
+++ b/ack.el
@@ -60,7 +60,7 @@
                  (executable-find "ack")
                  "ack"))
         (args (when (< emacs-major-version 24)
-                "--nocolor --column ")))
+                "--nocolor ")))
     (concat (file-name-nondirectory ack) " " args))
   "The default ack command for \\[ack].
 
@@ -158,12 +158,12 @@ This gets tacked on the end of the generated 
expressions.")
     (list file)))
 
 (defconst ack-regexp-alist
-  '(;; none grouping line (--nogroup or --noheading)
-    
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     1 3 (ack--column-start . ack--column-end))
-    ;; grouping line (--group or --heading)
+  '(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      ack--file 1 (ack--column-start . ack--column-end))
+    ;; none grouping line (--nogroup or --noheading)
+    
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
+     1 3 (ack--column-start . ack--column-end))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit 5b87a3e075ef777a8ed44245d5e05f35cf1828b9
Author: Leo Liu <address@hidden>
Date:   Fri Sep 28 23:37:00 2012 +0800

    Fix ack-regexp-alist for emacs-23
    
    In emacs 23, last matching element in ack-regexp-alist wins.

diff --git a/ack.el b/ack.el
index 61f7f29..d9db9ba 100644
--- a/ack.el
+++ b/ack.el
@@ -60,7 +60,7 @@
                  (executable-find "ack")
                  "ack"))
         (args (when (< emacs-major-version 24)
-                "--nocolor ")))
+                "--nocolor --column ")))
     (concat (file-name-nondirectory ack) " " args))
   "The default ack command for \\[ack].
 
@@ -158,12 +158,12 @@ This gets tacked on the end of the generated 
expressions.")
     (list file)))
 
 (defconst ack-regexp-alist
-  '(;; grouping line (--group or --heading)
-    ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
-     ack--file 1 (ack--column-start . ack--column-end))
-    ;; none grouping line (--nogroup or --noheading)
+  '(;; none grouping line (--nogroup or --noheading)
     
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      1 3 (ack--column-start . ack--column-end))
+    ;; grouping line (--group or --heading)
+    ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
+     ack--file 1 (ack--column-start . ack--column-end))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit 9947b8385420010495fad05bbcd42d73a46b49c3
Author: Leo Liu <address@hidden>
Date:   Fri Sep 28 18:48:36 2012 +0800

    Properly fontify file names in grouping output

diff --git a/ack.el b/ack.el
index a5ca03a..61f7f29 100644
--- a/ack.el
+++ b/ack.el
@@ -147,10 +147,14 @@ This gets tacked on the end of the generated 
expressions.")
                (forward-line -1)
                (looking-at-p "^--$")))
       (setq file (or (get-text-property (line-beginning-position) 'ack-file)
-                     (buffer-substring-no-properties
-                      (line-beginning-position) (line-end-position)))))
+                     (progn
+                       (put-text-property (line-beginning-position)
+                                          (line-end-position)
+                                          'font-lock-face 
compilation-info-face)
+                       (buffer-substring-no-properties
+                        (line-beginning-position) (line-end-position))))))
     (put-text-property (line-beginning-position)
-                       (1+ (line-end-position)) 'ack-file file)
+                       (min (1+ (line-end-position)) (point-max)) 'ack-file 
file)
     (list file)))
 
 (defconst ack-regexp-alist

commit b81dc1690b3cfd4153e7570bdae77894fbc9e0fa
Author: Leo Liu <address@hidden>
Date:   Fri Sep 28 13:33:32 2012 +0800

    Fixes for column number handling

diff --git a/ack.el b/ack.el
index c134846..a5ca03a 100644
--- a/ack.el
+++ b/ack.el
@@ -78,6 +78,9 @@ environment variable and ~/.ackrc, which you can disable by 
the
 (defvar ack-first-column 0
   "Value to use for `compilation-first-column' in ack buffers.")
 
+(defvar ack-error-screen-columns nil
+  "Value to use for `compilation-error-screen-columns' in ack buffers.")
+
 ;; Used implicitly by `define-compilation-mode'
 (defvar ack-error "ack match"
   "Stem of message to print when no matches are found.")
@@ -114,12 +117,18 @@ This gets tacked on the end of the generated 
expressions.")
   (defvar ack--column-end 'ack--column-end))
 
 (defun ack--column-start ()
-  (let* ((beg (match-end 0))
-         (end (save-excursion
-                (goto-char beg)
-                (line-end-position)))
-         (mbeg (text-property-any beg end 'ack-color t)))
-    (when mbeg (- mbeg beg))))
+  (or (let* ((beg (match-end 0))
+             (end (save-excursion
+                    (goto-char beg)
+                    (line-end-position)))
+             (mbeg (text-property-any beg end 'ack-color t)))
+        (when mbeg (- mbeg beg)))
+      ;; Use column number from `ack' itself if available
+      (when (match-string 4)
+        (put-text-property (match-beginning 4)
+                           (match-end 4)
+                           'font-lock-face compilation-column-face)
+        (1- (string-to-number (match-string 4))))))
 
 (defun ack--column-end ()
   (let* ((beg (match-end 0))
@@ -146,10 +155,10 @@ This gets tacked on the end of the generated 
expressions.")
 
 (defconst ack-regexp-alist
   '(;; grouping line (--group or --heading)
-    ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:[1-9][0-9]*\\2\\)?"
+    ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      ack--file 1 (ack--column-start . ack--column-end))
     ;; none grouping line (--nogroup or --noheading)
-    ("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\([1-9][0-9]*\\)\\2\\)?"
+    
("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\(?4:[1-9][0-9]*\\)\\2\\)?"
      1 3 (ack--column-start . ack--column-end))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")

commit 89d510f78de51c2300596577a5469428a105ccbf
Author: Leo Liu <address@hidden>
Date:   Fri Sep 28 10:00:00 2012 +0800

    Fix last change

diff --git a/README.rst b/README.rst
index ded6488..5178186 100644
--- a/README.rst
+++ b/README.rst
@@ -29,6 +29,7 @@ Completion
 Place ``pcmpl-ack.el`` in the ``load-path`` and add::
 
   (autoload 'pcomplete/ack "pcmpl-ack")
+  (autoload 'pcomplete/ack-grep "pcmpl-ack")
 
 to your init file. After this you will be able complete ``ack``
 options while ``M-x ack`` or in shell/eshell.
@@ -45,3 +46,7 @@ key bindings may be useful:
 
 #. ``M-I`` => insert a template for case-insensitive file name search
 #. ``TAB`` => completion for ack options
+
+Contributors
+------------
+Phillip Lord
diff --git a/ack.el b/ack.el
index 8ad3c75..c134846 100644
--- a/ack.el
+++ b/ack.el
@@ -168,7 +168,8 @@ This gets tacked on the end of the generated expressions.")
   "Insert a template for case-insensitive filename search."
   (interactive)
   (delete-minibuffer-contents)
-  (skeleton-insert '(nil "ack -g '(?i:" _ ")'")))
+  (let ((ack (or (car (split-string ack-command nil t)) "ack")))
+    (skeleton-insert '(nil ack " -g '(?i:" _ ")'"))))
 
 (defvar ack-minibuffer-local-map
   (let ((map (make-sparse-keymap)))
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
index ab98150..ace80d2 100644
--- a/pcmpl-ack.el
+++ b/pcmpl-ack.el
@@ -152,5 +152,8 @@ long options."
          (t (pcomplete-opt pcmpl-ack-short-options)))
       (pcomplete-here* (pcomplete-dirs-or-entries)))))
 
+;;;###autoload
+(defalias 'pcomplete/ack-grep 'pcomplete/ack)
+
 (provide 'pcmpl-ack)
 ;;; pcmpl-ack.el ends here

commit a1e6f9ca64d7fc81c000b03b77d5d43497aa7dd2
Author: Phillip Lord <address@hidden>
Date:   Fri Sep 28 09:11:54 2012 +0800

    Add support for ack-grep variant (tiny change)

diff --git a/ack.el b/ack.el
index 299ac47..8ad3c75 100644
--- a/ack.el
+++ b/ack.el
@@ -54,9 +54,14 @@
   :type 'boolean
   :group 'ack)
 
-(defcustom ack-command (if (>= emacs-major-version 24)
-                           "ack "
-                         "ack --nocolor ")
+(defcustom ack-command
+  ;; Note: on GNU/Linux ack may be renamed to ack-grep
+  (let ((ack (or (executable-find "ack-grep")
+                 (executable-find "ack")
+                 "ack"))
+        (args (when (< emacs-major-version 24)
+                "--nocolor ")))
+    (concat (file-name-nondirectory ack) " " args))
   "The default ack command for \\[ack].
 
 Note also options to ack can be specified in ACK_OPTIONS

commit 3555767aeac82d0f3d9f85ae13078207927a99b2
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 29 06:34:07 2012 +0400

    Fix #68
    
    While we're at it, allow empty lines inside a continued expression.

diff --git a/js2-mode.el b/js2-mode.el
index 89e4c53..0281531 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9922,16 +9922,19 @@ a comma)."
   (save-excursion
     (back-to-indentation)
     (or (js2-looking-at-operator-p)
-        ;; comment
-        (and (js2-re-search-backward "\n" nil t)
-            (progn
-              (skip-chars-backward " \t")
-               (unless (bolp)
-                 (backward-char)
-                 (and (js2-looking-at-operator-p)
-                      (and (progn
-                             (backward-char)
-                             (not (looking-at 
"\\*\\|++\\|--\\|/[/*]")))))))))))
+        (when (catch 'found
+                (while (and (re-search-backward "\n" nil t)
+                            (let ((state (syntax-ppss)))
+                              (when (nth 4 state)
+                                (goto-char (nth 8 state))) ;; skip comments
+                              (skip-chars-backward " \t")
+                              (if (bolp)
+                                  t
+                                (throw 'found t))))))
+          (backward-char)
+          (when (js2-looking-at-operator-p)
+            (backward-char)
+            (not (looking-at "\\*\\|++\\|--\\|/[/*]")))))))
 
 (defun js2-end-of-do-while-loop-p ()
   "Returns non-nil if word after point is `while' of a do-while
@@ -10393,10 +10396,10 @@ If so, we don't ever want to use bounce-indent."
         ;; This has to be set before calling parse-partial-sexp below.
         (inhibit-point-motion-hooks t))
     (setq parse-status (save-excursion
-                          (syntax-ppss (point-at-bol)))
+                         (syntax-ppss (point-at-bol)))
           offset (- (point) (save-excursion
-                               (back-to-indentation)
-                               (point))))
+                              (back-to-indentation)
+                              (point))))
     (js2-with-underscore-as-word-syntax
      (if (nth 4 parse-status)
          (js2-lineup-comment parse-status)

commit 1b19cbe7b746467b97927a55078f0a7465991e64
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 29 06:34:07 2012 +0400

    Fix #68
    
    While we're at it, allow empty lines inside a continued expression.

diff --git a/js2-mode.el b/js2-mode.el
index a1a3ba3..365bfa7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9658,13 +9658,19 @@ and comments have been removed."
   (save-excursion
     (back-to-indentation)
     (or (js2-looking-at-operator-p)
-        (when (js2-re-search-backward "\n" nil t)  ;; skip comments
-          (skip-chars-backward " \t")
-          (unless (bolp) ;; previous line is empty
+        (when (catch 'found
+                (while (and (re-search-backward "\n" nil t)
+                            (let ((state (syntax-ppss)))
+                              (when (nth 4 state)
+                                (goto-char (nth 8 state))) ;; skip comments
+                              (skip-chars-backward " \t")
+                              (if (bolp)
+                                  t
+                                (throw 'found t))))))
+          (backward-char)
+          (when (js2-looking-at-operator-p)
             (backward-char)
-            (when (js2-looking-at-operator-p)
-              (backward-char)
-              (not (looking-at "\\*\\|++\\|--\\|/[/*]"))))))))
+            (not (looking-at "\\*\\|++\\|--\\|/[/*]")))))))
 
 (defun js2-end-of-do-while-loop-p ()
   "Return non-nil if word after point is `while' of a do-while
@@ -10108,10 +10114,10 @@ If so, we don't ever want to use bounce-indent."
         ;; This has to be set before calling parse-partial-sexp below.
         (inhibit-point-motion-hooks t))
     (setq parse-status (save-excursion
-                          (syntax-ppss (point-at-bol)))
+                         (syntax-ppss (point-at-bol)))
           offset (- (point) (save-excursion
-                               (back-to-indentation)
-                               (point))))
+                              (back-to-indentation)
+                              (point))))
     (js2-with-underscore-as-word-syntax
      (if (nth 4 parse-status)
          (js2-lineup-comment parse-status)

commit d529164cfe20b65d1389880981d4ec1f6fb86acb
Author: Leo Liu <address@hidden>
Date:   Thu Sep 27 22:05:47 2012 +0800

    Make it run on emacs-23

diff --git a/ack.el b/ack.el
index 6ea84b3..299ac47 100644
--- a/ack.el
+++ b/ack.el
@@ -28,8 +28,9 @@
 ;;; Code:
 
 (require 'compile)
-(require 'ansi-color)
-(autoload 'shell-completion-vars "shell")
+(when (>= emacs-major-version 24)
+  (require 'ansi-color)
+  (autoload 'shell-completion-vars "shell"))
 
 (defgroup ack nil
   "Run `ack' and display the results."
@@ -53,7 +54,9 @@
   :type 'boolean
   :group 'ack)
 
-(defcustom ack-command "ack "
+(defcustom ack-command (if (>= emacs-major-version 24)
+                           "ack "
+                         "ack --nocolor ")
   "The default ack command for \\[ack].
 
 Note also options to ack can be specified in ACK_OPTIONS
@@ -101,6 +104,10 @@ This function is called from `compilation-filter-hook'."
   "Additional things to highlight in ack output.
 This gets tacked on the end of the generated expressions.")
 
+(when (< emacs-major-version 24)
+  (defvar ack--column-start 'ack--column-start)
+  (defvar ack--column-end 'ack--column-end))
+
 (defun ack--column-start ()
   (let* ((beg (match-end 0))
          (end (save-excursion
@@ -149,7 +156,8 @@ This gets tacked on the end of the generated expressions.")
        'compilation-info)
   (set (make-local-variable 'compilation-error-regexp-alist)
        ack-regexp-alist)
-  (add-hook 'compilation-filter-hook 'ack-filter nil t))
+  (when (boundp 'compilation-filter-hook)
+    (add-hook 'compilation-filter-hook 'ack-filter nil t)))
 
 (defun ack-skel-file ()
   "Insert a template for case-insensitive filename search."
@@ -160,7 +168,9 @@ This gets tacked on the end of the generated expressions.")
 (defvar ack-minibuffer-local-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
-    (define-key map "\t" 'completion-at-point)
+    (define-key map "\t" (if (>= emacs-major-version 24)
+                             'completion-at-point
+                           'pcomplete))
     (define-key map "\M-I" 'ack-skel-file)
     (define-key map "'" 'skeleton-pair-insert-maybe)
     map)
@@ -187,7 +197,9 @@ minibuffer:
 
 \\{ack-minibuffer-local-map}"
   (interactive
-   (list (minibuffer-with-setup-hook 'shell-completion-vars
+   (list (minibuffer-with-setup-hook (if (>= emacs-major-version 24)
+                                         'shell-completion-vars
+                                       'pcomplete-shell-setup)
            (read-from-minibuffer "Run ack (like this): "
                                  ack-command ack-minibuffer-local-map
                                  nil 'ack-history))

commit 67d7e79306ee83ec15b8711c092e616bf1ba2fe8
Author: Leo Liu <address@hidden>
Date:   Thu Sep 27 09:40:06 2012 +0800

    Release version 0.6

diff --git a/README.rst b/README.rst
index 31cf7d3..ded6488 100644
--- a/README.rst
+++ b/README.rst
@@ -4,8 +4,8 @@
  
 From http://betterthangrep.com/
 
-    ack is a tool like grep, designed for programmers with large trees of
-    heterogeneous source code.
+    ack is a tool like grep, designed for programmers with large trees
+    of heterogeneous source code.
 
     ack is written purely in Perl, and takes advantage of the power of
     Perl's regular expressions.
@@ -13,12 +13,35 @@ From http://betterthangrep.com/
 Feature requests and bug reports are welcome. Thanks.
 
 Install
-=======
+-------
 
-Place ``ack.el`` in the load-path and put ``(require 'ack)`` or
-``(autoload 'ack "ack" nil t)`` in your ``.emacs``.
+Place ``ack.el`` in the ``load-path`` and add to your init file::
+
+  (require 'ack)
+
+or::
+
+ (autoload 'ack "ack" nil t)
+
+Completion
+~~~~~~~~~~
+
+Place ``pcmpl-ack.el`` in the ``load-path`` and add::
+
+  (autoload 'pcomplete/ack "pcmpl-ack")
+
+to your init file. After this you will be able complete ``ack``
+options while ``M-x ack`` or in shell/eshell.
 
 Usage
-=====
+-----
+
+#. ``M-x ack`` and provide a pattern to search.
+#. ``C-u M-x ack`` like ``M-x ack`` but allow you to select a
+   directory to search.
+
+While reading ack command and args from the minibuffer, the following
+key bindings may be useful:
 
-``M-x ack``
+#. ``M-I`` => insert a template for case-insensitive file name search
+#. ``TAB`` => completion for ack options
diff --git a/ack.el b/ack.el
index 1e8cbab..6ea84b3 100644
--- a/ack.el
+++ b/ack.el
@@ -5,7 +5,7 @@
 ;; Author: Leo Liu <address@hidden>
 ;; Keywords: tools, processes, convenience
 ;; Created: 2012-03-24
-;; Version: 0.5
+;; Version: 0.6
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by

commit 2f5168af1b4cf2ad6274ecc6fb36cc0e2b1670c5
Author: Leo Liu <address@hidden>
Date:   Thu Sep 27 09:22:42 2012 +0800

    Default DIRECTORY arg to ack to current project root

diff --git a/ack.el b/ack.el
index 62ba3b5..1e8cbab 100644
--- a/ack.el
+++ b/ack.el
@@ -36,6 +36,17 @@
   :group 'tools
   :group 'processes)
 
+(defcustom ack-project-pattern-list
+  (list (concat "\\`" (regexp-quote dir-locals-file) "\\'")
+        "\\`Project\\.ede\\'"
+        "\\.xcodeproj\\'"         ; xcode
+        "\\`\\.ropeproject\\'"    ; python rope
+        ;; ".git" ".svn" ".hg" ".bzr" ".CVS"
+        "\\`\\.\\(?:CVS\\|bzr\\|git\\|hg\\|svn\\)\\'")
+  "A list of regexps that match files in a project root."
+  :type '(repeat string)
+  :group 'ack)
+
 ;; Used implicitly by `define-compilation-mode'
 (defcustom ack-scroll-output nil
   "Similar to `compilation-scroll-output' but for the *Ack* buffer."
@@ -155,10 +166,21 @@ This gets tacked on the end of the generated 
expressions.")
     map)
   "Keymap used for reading `ack' command and args in minibuffer.")
 
+(defun ack-guess-project-root (start-directory &optional regexp)
+  (let ((regexp (or regexp
+                    (mapconcat 'identity ack-project-pattern-list "\\|")))
+        (parent (file-name-directory
+                 (directory-file-name (expand-file-name start-directory)))))
+    (if (directory-files start-directory nil regexp)
+        start-directory
+      (unless (equal parent start-directory)
+        (ack-guess-project-root parent regexp)))))
+
 ;;;###autoload
 (defun ack (command-args &optional directory)
   "Run ack using COMMAND-ARGS and collect output in a buffer.
-With prefix, ask for the DIRECTORY to run ack.
+With prefix, ask for the DIRECTORY to run ack; otherwise the
+current project root is used.
 
 The following keys are available while reading from the
 minibuffer:
@@ -169,8 +191,9 @@ minibuffer:
            (read-from-minibuffer "Run ack (like this): "
                                  ack-command ack-minibuffer-local-map
                                  nil 'ack-history))
-         (and current-prefix-arg
-              (read-directory-name "In directory: " nil nil t))))
+         (if current-prefix-arg
+             (read-directory-name "In directory: " nil nil t)
+           (ack-guess-project-root default-directory))))
   (let ((default-directory (expand-file-name
                             (or directory default-directory))))
     (compilation-start command-args 'ack-mode)))

commit acbeab6ed191f7b7013c7d5b0d3bb2e230fc5673
Author: Leo Liu <address@hidden>
Date:   Wed Sep 26 15:28:40 2012 +0800

    Add completion support for ack

diff --git a/ack.el b/ack.el
index a9eb7ef..62ba3b5 100644
--- a/ack.el
+++ b/ack.el
@@ -29,6 +29,7 @@
 
 (require 'compile)
 (require 'ansi-color)
+(autoload 'shell-completion-vars "shell")
 
 (defgroup ack nil
   "Run `ack' and display the results."
@@ -41,7 +42,7 @@
   :type 'boolean
   :group 'ack)
 
-(defcustom ack-command "ack -- "
+(defcustom ack-command "ack "
   "The default ack command for \\[ack].
 
 Note also options to ack can be specified in ACK_OPTIONS
@@ -139,15 +140,35 @@ This gets tacked on the end of the generated 
expressions.")
        ack-regexp-alist)
   (add-hook 'compilation-filter-hook 'ack-filter nil t))
 
+(defun ack-skel-file ()
+  "Insert a template for case-insensitive filename search."
+  (interactive)
+  (delete-minibuffer-contents)
+  (skeleton-insert '(nil "ack -g '(?i:" _ ")'")))
+
+(defvar ack-minibuffer-local-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map minibuffer-local-map)
+    (define-key map "\t" 'completion-at-point)
+    (define-key map "\M-I" 'ack-skel-file)
+    (define-key map "'" 'skeleton-pair-insert-maybe)
+    map)
+  "Keymap used for reading `ack' command and args in minibuffer.")
+
 ;;;###autoload
 (defun ack (command-args &optional directory)
   "Run ack using COMMAND-ARGS and collect output in a buffer.
 With prefix, ask for the DIRECTORY to run ack.
 
-\\{ack-mode-map}"
+The following keys are available while reading from the
+minibuffer:
+
+\\{ack-minibuffer-local-map}"
   (interactive
-   (list (read-from-minibuffer "Run ack (like this): "
-                               ack-command nil nil 'ack-history)
+   (list (minibuffer-with-setup-hook 'shell-completion-vars
+           (read-from-minibuffer "Run ack (like this): "
+                                 ack-command ack-minibuffer-local-map
+                                 nil 'ack-history))
          (and current-prefix-arg
               (read-directory-name "In directory: " nil nil t))))
   (let ((default-directory (expand-file-name
diff --git a/pcmpl-ack.el b/pcmpl-ack.el
new file mode 100644
index 0000000..ab98150
--- /dev/null
+++ b/pcmpl-ack.el
@@ -0,0 +1,156 @@
+;;; pcmpl-ack.el --- completion for ack tool
+
+;; Copyright (C) 2012  Leo Liu
+
+;; Author: Leo Liu <address@hidden>
+;; Keywords: tools, processes, convenience
+;; Created: 2012-09-26
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Provide pcompletion support for the cli tool `ack' which can be
+;; downloaded from http://betterthangrep.com.
+;;
+;; Install:
+;;   (autoload 'pcomplete/ack "pcmpl-ack")
+;;
+;; Usage:
+;;   - To complete short options type '-' first
+;;   - To complete long options type '--' first
+;;   - Color name completion is also supported following
+;;       --color-filename=, --color-match= and --color-lineno=.
+
+;;; Code:
+
+(require 'pcomplete)
+
+(defvar pcmpl-ack-short-options
+  (mapconcat (lambda (o) (substring o 1))
+             '("-a" "-A" "-B" "-C" "-c" "-f" "-G" "-g"
+               "-H" "-h" "-i" "-l" "-L" "-m" "-n"
+               "-o" "-Q" "-r" "-R"
+               "-u" "-v" "-w" "-1")
+             "")
+  "Short options for the `ack' command.")
+
+(defvar pcmpl-ack-long-options
+  '("--after-context="
+    "--all-types"
+    "--before-context="
+    "--break"
+    "--nobreak"
+    "--color"
+    "--nocolor"
+    "--colour"
+    "--nocolour"
+    "--color-filename="
+    "--color-match="
+    "--color-lineno="
+    "--column"
+    "--context="
+    "--count"
+    "--env"
+    "--noenv"
+    "--files-with-matches"
+    "--files-without-matches"
+    "--flush"
+    "--follow"
+    "--nofollow"
+    "--group"
+    "--nogroup"
+    "--heading"
+    "--noheading"
+    "--ignore-case"
+    "--ignore-dir="
+    "--noignore-dir="
+    "--invert-match"
+    "--line="
+    "--literal"
+    "--match"
+    "--max-count="
+    "--no-filename"
+    "--output="
+    "--pager="
+    "--nopager"
+    "--passthru"
+    "--print0"
+    "--recurse"
+    "--norecurse"
+    "--smart-case"
+    "--nosmart-case"
+    "--sort-files"
+    "--type="
+    "--type-add"
+    "--type-set"
+    "--unrestricted"
+    "--with-filename"
+    "--word-regexp"
+    "--help"
+    "--help-types"
+    "--man"
+    "--thpppt"
+    "--version")
+  "Long options for the `ack' command.")
+
+(defvar pcmpl-ack-color-options
+  '("clear"
+    "reset"
+    "dark"
+    "bold"
+    "underline"
+    "underscore"
+    "blink"
+    "reverse"
+    "concealed"
+    "black"
+    "red"
+    "green"
+    "yellow"
+    "blue"
+    "magenta"
+    "on_black"
+    "on_red"
+    "on_green"
+    "on_yellow"
+    "on_blue"
+    "on_magenta"
+    "on_cyan"
+    "on_white")
+  "Color names for the `ack' command.")
+
+;;;###autoload
+(defun pcomplete/ack ()
+  "Completion for the `ack' command.
+Start an argument with '-' to complete short options and '--' for
+long options."
+  ;; No space after =
+  (add-to-list 'pcomplete-suffix-list ?=)
+  (while t
+    (if (pcomplete-match "^-" 0)
+        (cond
+         ((pcomplete-match "^--color-\\w+=\\(\\S-*\\)" 0)
+          (pcomplete-here* pcmpl-ack-color-options
+                           (pcomplete-match-string 1 0) t))
+         ((pcomplete-match "^--\\(?:no\\)?ignore-dir=\\(\\S-*\\)" 0)
+          (pcomplete-here* (pcomplete-dirs)
+                           (pcomplete-match-string 1 0) t))
+         ((pcomplete-match "^--" 0)
+          (pcomplete-here* pcmpl-ack-long-options))
+         (t (pcomplete-opt pcmpl-ack-short-options)))
+      (pcomplete-here* (pcomplete-dirs-or-entries)))))
+
+(provide 'pcmpl-ack)
+;;; pcmpl-ack.el ends here

commit 061fde1ff9d88407908c349146fbee568bf0b632
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 22 23:06:47 2012 +0400

    js2-mode-extend-comment: Move (js2-indent-line) outside the (cond)

diff --git a/js2-mode.el b/js2-mode.el
index 7a876a8..a1a3ba3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10710,9 +10710,9 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
               (and (zerop (forward-line 1))
                    (looking-at "\\s-*//"))))
       (indent-to col)
-      (insert "// "))
-     ;; Don't need to extend the comment after all.
-     (js2-indent-line))))
+      (insert "// ")))
+    ;; Don't need to extend the comment after all.
+    (js2-indent-line)))
 
 (defun js2-beginning-of-line ()
   "Toggles point between bol and first non-whitespace char in line.

commit 0a84731c4fe8b85482ba10637def80b932b112e9
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 22 22:51:52 2012 +0400

    Simplify error list annotation and destructuring

diff --git a/js2-mode.el b/js2-mode.el
index 9710b56..7a876a8 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10203,7 +10203,7 @@ highlighting features of `js2-mode'."
             (lst type)
             "Add diagnostic TYPE and line number to errs list"
             (mapcar (lambda (err)
-                      (cons err (list type (line-number-at-pos (nth 1 err)))))
+                      (list err type (line-number-at-pos (nth 1 err))))
                     lst)))
     (let* ((srcbuf (current-buffer))
            (errbuf (get-buffer-create "*js-lint*"))
@@ -10219,7 +10219,7 @@ highlighting features of `js2-mode'."
         (let ((inhibit-read-only t))
           (erase-buffer)
           (dolist (err all-errs)
-            (destructuring-bind ((msg-key beg end &rest) . (type line)) err
+            (destructuring-bind ((msg-key beg end &rest) type line) err
               (insert-text-button
                (format "line %d: %s" line (js2-get-msg msg-key))
                'face type

commit 45e8cca8bd8ffc6f4d22d38d18d04576899ca7e5
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 22 17:31:20 2012 +0400

    Fix js2-display-error-list
    
    Regression from 14c6ea539b9ee7b98d0c6b870c23202798ba37b3

diff --git a/js2-mode.el b/js2-mode.el
index f433db7..9710b56 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10203,8 +10203,7 @@ highlighting features of `js2-mode'."
             (lst type)
             "Add diagnostic TYPE and line number to errs list"
             (mapcar (lambda (err)
-                      (append err (list type
-                                        (line-number-at-pos (nth 1 err)))))
+                      (cons err (list type (line-number-at-pos (nth 1 err)))))
                     lst)))
     (let* ((srcbuf (current-buffer))
            (errbuf (get-buffer-create "*js-lint*"))
@@ -10215,12 +10214,12 @@ highlighting features of `js2-mode'."
                       (when js2-mode-ast (js2-ast-root-warnings js2-mode-ast))
                       'js2-warning))  ; must be a valid face name
            (all-errs (sort (append errors warnings)
-                           (lambda (e1 e2) (< (nth 1 e1) (nth 1 e2))))))
+                           (lambda (e1 e2) (< (cadar e1) (cadar e2))))))
       (with-current-buffer errbuf
         (let ((inhibit-read-only t))
           (erase-buffer)
           (dolist (err all-errs)
-            (destructuring-bind (msg-key beg end type line) err
+            (destructuring-bind ((msg-key beg end &rest) . (type line)) err
               (insert-text-button
                (format "line %d: %s" line (js2-get-msg msg-key))
                'face type

commit 7b9dd8ff21072c833ec4838868bb7b69a1a6d955
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 22 08:00:18 2012 +0400

    Don't need `funcall` where FUNCTION is constant

diff --git a/js2-mode.el b/js2-mode.el
index d2c06c4..f433db7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1269,7 +1269,7 @@ First match-group is the leading whitespace.")
 
 ;; TODO(stevey):  construct this table at compile-time.
 (defmacro js2-msg (key &rest strings)
-  `(puthash ,key (funcall #'concat ,@strings)
+  `(puthash ,key (concat ,@strings)
             js2-message-table))
 
 (defun js2-get-msg (msg-key)
@@ -10215,8 +10215,7 @@ highlighting features of `js2-mode'."
                       (when js2-mode-ast (js2-ast-root-warnings js2-mode-ast))
                       'js2-warning))  ; must be a valid face name
            (all-errs (sort (append errors warnings)
-                           (lambda (e1 e2)
-                             (funcall '< (nth 1 e1) (nth 1 e2))))))
+                           (lambda (e1 e2) (< (nth 1 e1) (nth 1 e2))))))
       (with-current-buffer errbuf
         (let ((inhibit-read-only t))
           (erase-buffer)

commit be599424f028dbde8d37e81d5dcd8e9737a6ffa2
Author: Dmitry Gutov <address@hidden>
Date:   Wed Sep 12 05:33:59 2012 +0400

    Remove run-mode-hooks call, define-derived-mode already does that

diff --git a/js2-mode.el b/js2-mode.el
index e37b901..d2c06c4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10372,10 +10372,6 @@ Selecting an error will jump it to the corresponding 
source-buffer error.
   (set (make-local-variable 'line-move-ignore-invisible) t)
   (set (make-local-variable 'forward-sexp-function) #'js2-mode-forward-sexp)
 
-  (if (fboundp 'run-mode-hooks)
-      (run-mode-hooks 'js2-mode-hook)
-    (run-hooks 'js2-mode-hook))
-
   (setq js2-mode-functions-hidden nil
         js2-mode-comments-hidden nil
         js2-mode-buffer-dirty-p t

commit 52241c5544294964b9e9d2f0b61ace82384779a4
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 06:03:10 2012 +0400

    you -> your

diff --git a/README.md b/README.md
index e605dae..a8f5ac8 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Installation
 
 Then put js2-mode.elc into your site-lisp directory.
 
-In you emacs config:
+In your emacs config:
 
     (autoload 'js2-mode "js2-mode" nil t)
     (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

commit be0394e00f530fdd999f13e3d653b3eba8977434
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 06:03:10 2012 +0400

    you -> your

diff --git a/README.md b/README.md
index 4ff9786..82c9b52 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Installation
 
 Then put js2-mode.elc into your site-lisp directory.
 
-In you emacs config:
+In your emacs config:
 
     (autoload 'js2-mode "js2-mode" nil t)
     (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

commit fef03725b09448959075b63b73c7e6ebe14b3a27
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 05:59:45 2012 +0400

    Move "the" outside the link

diff --git a/README.md b/README.md
index e67a00a..e605dae 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,7 @@ additional details.
 Emacs 22 and 23
 ===============
 
-This version requires Emacs 24. For backwards-compatible version, check out 
[the
-`master` branch](https://github.com/mooz/js2-mode/tree/master).
+This version requires Emacs 24. For backwards-compatible version, check out 
the [`master` branch](https://github.com/mooz/js2-mode/tree/master).
 
 Bugs
 ====

commit 6fb5901f57f031cf68280c34e31d455f7535546d
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 05:58:19 2012 +0400

    Add section "Emacs 22 and 23"

diff --git a/README.md b/README.md
index 3964091..e67a00a 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Description
 
 An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
 
-For the list of user-visible changes, see
+For some of the user-visible changes, see
 [Changes from the original 
mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
 
 Installation
@@ -11,6 +11,7 @@ Installation
 
     $ git clone git://github.com/mooz/js2-mode.git
     $ cd js2-mode
+    $ git checkout emacs24
     $ emacs --batch -f batch-byte-compile js2-mode.el
 
 Then put js2-mode.elc into your site-lisp directory.
@@ -23,6 +24,12 @@ In you emacs config:
 See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for
 additional details.
 
+Emacs 22 and 23
+===============
+
+This version requires Emacs 24. For backwards-compatible version, check out 
[the
+`master` branch](https://github.com/mooz/js2-mode/tree/master).
+
 Bugs
 ====
 

commit 5efdc9a2d8bdba4515390e8143fecad22ae28cd7
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 05:54:25 2012 +0400

    Add section "Emacs 24"

diff --git a/README.md b/README.md
index 3964091..4ff9786 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Description
 
 An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
 
-For the list of user-visible changes, see
+For some of the user-visible changes, see
 [Changes from the original 
mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
 
 Installation
@@ -23,6 +23,11 @@ In you emacs config:
 See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for
 additional details.
 
+Emacs 24
+========
+
+The version from the [branch 
`emacs24`](https://github.com/mooz/js2-mode/tree/emacs24) is recommended.
+
 Bugs
 ====
 

commit bbb15a4a6c03a2e64ca6037fddb92e9f3df3c1c3
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 11 05:13:30 2012 +0400

    Tweak `js2-line-break` behavior, bind it to M-j
    
    js2-indent-on-enter-key, js2-enter-indents-newline: Remove.
    js2-line-break: Always indent the line.
    js2-mode-split-string: Use js2-indent-line. Remove the variable 
quote-string.
    js2-mode-extend-comment: Support block comments at the end of the line.
    Delete whitespace around the newline. Always indent the line.

diff --git a/js2-mode.el b/js2-mode.el
index cfbbdc2..e37b901 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -252,18 +252,6 @@ lines, it won't be indented additionally:
   :type 'symbol)
 (js2-mark-safe-local 'js2-pretty-multiline-declarations 'symbolp)
 
-(defcustom js2-indent-on-enter-key nil
-  "Non-nil to have Enter/Return key indent the line.
-This is unusual for Emacs modes but common in IDEs like Eclipse."
-  :type 'boolean
-  :group 'js2-mode)
-
-(defcustom js2-enter-indents-newline nil
-  "Non-nil to have Enter/Return key indent the newly-inserted line.
-This is unusual for Emacs modes but common in IDEs like Eclipse."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-idle-timer-delay 0.2
   "Delay in secs before re-parsing after user makes changes.
 Multiplied by `js2-dynamic-idle-timer-adjust', which see."
@@ -1126,6 +1114,7 @@ another file, or you've got a potential bug."
   (let ((map (make-sparse-keymap))
         keys)
     (define-key map [mouse-1] #'js2-mode-show-node)
+    (define-key map (kbd "M-j") #'js2-line-break)
     (define-key map (kbd "C-c C-e") #'js2-mode-hide-element)
     (define-key map (kbd "C-c C-s") #'js2-mode-show-element)
     (define-key map (kbd "C-c C-a") #'js2-mode-show-all)
@@ -10640,7 +10629,10 @@ This ensures that the counts and `next-error' are 
correct."
 (defalias #'js2-echo-help #'js2-echo-error)
 
 (defun js2-line-break (&optional soft)
-  "Break line at point."
+  "Break line at point and indent, continuing comment if within one.
+If inside a string, and `js2-concat-multiline-strings' is not
+nil, turn it into concatenation."
+  (interactive)
   (let ((parse-status (syntax-ppss)))
     (cond
      ;; Check if we're inside a string.
@@ -10650,46 +10642,36 @@ This ensures that the counts and `next-error' are 
correct."
         (insert "\n")))
      ;; Check if inside a block comment.
      ((nth 4 parse-status)
-      (js2-mode-extend-comment))
+      (js2-mode-extend-comment (nth 8 parse-status)))
      (t
-      (newline)))))
+      (newline-and-indent)))))
 
 (defun js2-mode-split-string (parse-status)
   "Turn a newline in mid-string into a string concatenation.
 PARSE-STATUS is as documented in `parse-partial-sexp'."
   (let* ((col (current-column))
          (quote-char (nth 3 parse-status))
-         (quote-string (string quote-char))
          (string-beg (nth 8 parse-status))
-         (at-eol (eq js2-concat-multiline-strings 'eol))
-         (indent (or
-                  (save-excursion
-                    (back-to-indentation)
-                    (if (looking-at "\\+")
-                        (current-column)))
-                  (save-excursion
-                    (goto-char string-beg)
-                    (if (looking-back "\\+\\s-+")
-                        (goto-char (match-beginning 0)))
-                    (current-column)))))
+         (at-eol (eq js2-concat-multiline-strings 'eol)))
     (insert quote-char)
     (if at-eol
         (insert " +\n")
       (insert "\n"))
-    ;; FIXME: This does not match the behavior of `js2-indent-line'.
-    (indent-to indent)
     (unless at-eol
       (insert "+ "))
-    (insert quote-string)
+    (js2-indent-line)
+    (insert quote-char)
     (when (eolp)
-      (insert quote-string)
+      (insert quote-char)
       (backward-char 1))))
 
-(defun js2-mode-extend-comment ()
+(defun js2-mode-extend-comment (start-pos)
   "Indent the line and, when inside a comment block, add comment prefix."
   (let (star single col first-line needs-close)
     (save-excursion
       (back-to-indentation)
+      (when (< (point) start-pos)
+        (goto-char start-pos))
       (cond
        ((looking-at "\\*[^/]")
         (setq star t
@@ -10718,6 +10700,7 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
                 (save-excursion
                   (skip-chars-forward " \t\r\n")
                   (not (eq (char-after) ?*))))))
+    (delete-horizontal-space)
     (insert "\n")
     (cond
      (star
@@ -10734,9 +10717,8 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
                    (looking-at "\\s-*//"))))
       (indent-to col)
       (insert "// "))
-     ;; don't need to extend the comment after all
-     (js2-enter-indents-newline
-      (js2-indent-line)))))
+     ;; Don't need to extend the comment after all.
+     (js2-indent-line))))
 
 (defun js2-beginning-of-line ()
   "Toggles point between bol and first non-whitespace char in line.

commit a54bd05a8f35ec42abf22dcca541571ef2f21e1a
Merge: c3ec4af cca2fab
Author: Dmitry Gutov <address@hidden>
Date:   Mon Sep 10 07:40:44 2012 +0400

    Merge branch 'master' into emacs24


commit 2619e05769df4b48c56bca513e8a371cf3d45231
Author: Lawrence Mitchell <address@hidden>
Date:   Sun Sep 9 18:35:19 2012 +0100

    Update copyright in line with ELPA version

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 4840f67..c33996c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -1,29 +1,26 @@
 ;;; f90-interface-browser.el --- Parse and browse f90 interfaces
 
-;; This file is NOT part of Emacs.
+;; Copyright (C) 2011, 2012  Free Software Foundation, Inc
 
-;; Copyright (C) 2011, 2012 Lawrence Mitchell <address@hidden>
-;; Filename: f90-interface-browser.el
+;; Author: Lawrence Mitchell <address@hidden>
 ;; Created: 2011-07-06
 ;; Available-from: http://github.com/wence-/f90-iface/
 ;; Version: 1.1
 
 ;; COPYRIGHT NOTICE
 
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2 of the
-;; License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more
-;; details. http://www.gnu.org/copyleft/gpl.html
-;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If you did not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;; You write (or work on) large, modern fortran code bases.  These

commit cca2fabf40a165b196b436cf371ebca7eaec7707
Author: Dmitry Gutov <address@hidden>
Date:   Sat Sep 8 20:06:49 2012 +0400

    Fix #66

diff --git a/js2-mode.el b/js2-mode.el
index ba112e5..89e4c53 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10410,9 +10410,9 @@ If so, we don't ever want to use bounce-indent."
               (not (js2-1-line-comment-continuation-p)))
          (js2-bounce-indent indent-col parse-status bounce-backwards))
         ;; just indent to the guesser's likely spot
-        (t (indent-line-to indent-col)))
-       (when (plusp offset)
-         (forward-char offset))))))
+        (t (indent-line-to indent-col))))
+     (when (plusp offset)
+       (forward-char offset)))))
 
 (defun js2-indent-region (start end)
   "Indent the region, but don't use bounce indenting."

commit c3ec4af58c12c787a8e09cdcd74b986e93e59964
Merge: 1482463 47dd40b
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 4 05:15:54 2012 +0400

    Merge branch 'master' into emacs24


commit 47dd40b100ecae0deef41a6533b402fec740e65d
Author: Dmitry Gutov <address@hidden>
Date:   Tue Sep 4 02:42:57 2012 +0400

    Fix #63

diff --git a/js2-mode.el b/js2-mode.el
index 7a8c744..ba112e5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11448,7 +11448,8 @@ With ARG, do it that many times.  Negative arg -N means
 move backward across N balanced expressions."
   (interactive "p")
   (setq arg (or arg 1))
-  (when js2-mode-buffer-dirty-p
+  (save-restriction
+    (widen) ;; `blink-matching-open' calls `narrow-to-region'
     (js2-reparse))
   (let ((scan-msg "Containing expression ends prematurely")
         node (start (point)) pos lp rp child)

commit b65328cc09e7c802ae29142ec5e7fa1f18ecacf1
Author: Andrew Hyatt <address@hidden>
Date:   Sun Sep 2 23:56:07 2012 -0400

    Made the max number of bytes transimssible 2^29 - 1 instead of 2^32 - 1.
    
    This is the maximum positive value an elisp integer can have on 32 bit
    machines.

diff --git a/websocket-test.el b/websocket-test.el
index c965033..19746fd 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -45,17 +45,13 @@
   "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"
   "'Hello' masked string example, taken from the RFC.")
 
-(defconst websocket-test-64-bit-p
-  (calc-eval '("2^32 <= $") 'pred most-positive-fixnum))
-
 (ert-deftest websocket-get-bytes ()
   (should (equal #x5 (websocket-get-bytes "\x5" 1)))
   (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
   (should (equal #xffffff
                  (websocket-get-bytes "\x0\x0\x0\x0\x0\xFF\xFF\xFF" 8)))
-  (when websocket-test-64-bit-p
-    (should-error (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)
-                  :type 'websocket-unparseable-frame))
+  (should-error (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)
+                :type 'websocket-unparseable-frame)
   (should-error (websocket-get-bytes "\x0\x0\x0" 3))
   (should-error (websocket-get-bytes "\x0" 2) :type 
'websocket-unparseable-frame))
 
@@ -276,10 +272,8 @@
   ;; help test websocket-to-bytes.
   (should (equal 30 (websocket-get-bytes (websocket-to-bytes 30 1) 1)))
   (should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
-  (let ((f (lambda () (websocket-to-bytes 70000 8))))
-    (if websocket-test-64-bit-p
-        (should (equal 70000 (websocket-get-bytes (funcall f) 8)))
-      (should-error (funcall f))))
+  (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
+  (should-error (websocket-to-bytes 536870912 8) :type 
'websocket-frame-too-large)
   (should-error (websocket-to-bytes 30 3))
   (should-error (websocket-to-bytes 300 1))
   ;; I'd like to test the error for 32-byte systems on 8-byte lengths,
@@ -295,7 +289,7 @@
              websocket-test-hello
              (websocket-encode-frame
               (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
-    (dolist (len (if websocket-test-64-bit-p '(200 70000) '(200 60000)))
+    (dolist (len '(200 70000))
       (let ((long-string (make-string len ?x)))
         (should (equal long-string
                        (websocket-frame-payload
diff --git a/websocket.el b/websocket.el
index 95a7eba..c340e63 100644
--- a/websocket.el
+++ b/websocket.el
@@ -198,13 +198,15 @@ This is based on the KEY from the Sec-WebSocket-Key 
header."
 Return the value as an unsigned integer.  The value N must be a
 power of 2, up to 8.
 
-We support getting frames up to 4294967295 bytes (2^32) long."
+We support getting frames up to 536870911 bytes (2^29 - 1),
+approximately 537M long."
   (if (= n 8)
     (let* ((32-bit-parts
             (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
            (cval
             (logior (lsh (aref 32-bit-parts 0) 32) (aref 32-bit-parts 1))))
-      (if (= (aref 32-bit-parts 0) 0)
+      (if (and (= (aref 32-bit-parts 0) 0)
+               (= (lsh (aref 32-bit-parts 1) -29) 0))
           cval
         (signal 'websocket-unparseable-frame
                 "Frame value found too large to parse!")))
@@ -229,7 +231,8 @@ We support getting frames up to 4294967295 bytes (2^32) 
long."
   "Encode the integer VAL in NBYTES of data.
 NBYTES much be a power of 2, up to 8.
 
-This supports encoding values up to "
+This supports encoding values up to 536870911 bytes (2^29 - 1),
+approximately 537M long."
   (when (and (< nbytes 8)
              (> val (expt 2 (* 8 nbytes))))
     ;; not a user-facing error, this must be caused from an error in
@@ -240,7 +243,7 @@ This supports encoding values up to "
       (progn
         (let ((hi-32bits (lsh val -32))
               (low-32bits (logand #xffffffff val)))
-          (when (> hi-32bits 0)
+          (when (or (> hi-32bits 0) (> (lsh low-32bits -29) 0))
             (signal 'websocket-frame-too-large val))
           (bindat-pack `((:val vec 2 u32))
                        `((:val . [,hi-32bits ,low-32bits])))))

commit 1482463fbd97acd81b29d9170d27080a2632de04
Merge: f26abe1 b02f4a0
Author: Dmitry Gutov <address@hidden>
Date:   Mon Sep 3 07:15:54 2012 +0400

    Merge branch 'master' into emacs24

diff --cc js2-mode.el
index f72114f,7a8c744..92392e3
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -11167,28 -11517,29 +11177,51 @@@ move backward across N balanced express
        (cons (when lp (+ abs-pos lp))
              (when rp (+ abs-pos rp)))))))
  
+ (defun js2-node-closest-child (parent point limit &optional before)
+   (let* ((parent-pos (js2-node-abs-pos parent))
+          (rpoint (- point parent-pos))
+          (rlimit (- limit parent-pos))
+          (min (min rpoint rlimit))
+          (max (max rpoint rlimit))
+          found)
+     (catch 'done
+       (js2-visit-ast
+        parent
+        (lambda (node end-p)
+          (if (eq node parent)
+              t
+            (let ((pos (js2-node-pos node)) ;; Both relative values.
+                  (end (+ (js2-node-pos node) (js2-node-len node))))
+              (when (and (>= pos min) (<= end max)
+                         (if before (< pos rpoint) (> end rpoint)))
+                (setq found node))
+              (when (> end rpoint)
+                (throw 'done nil)))
+            nil))))
+     found))
+ 
 +(defun js2-errors ()
 +  "Return a list of errors found."
 +  (and js2-mode-ast
 +       (js2-ast-root-errors js2-mode-ast)))
 +
 +(defun js2-warnings ()
 +  "Return a list of warnings found."
 +  (and js2-mode-ast
 +       (js2-ast-root-warnings js2-mode-ast)))
 +
 +(defun js2-have-errors-p ()
 +  "Return non-nil if any parse errors or warnings were found."
 +  (or (js2-errors) (js2-warnings)))
 +
 +(defun js2-errors-and-warnings ()
 +  "Return a copy of the concatenated errors and warnings lists.
 +They are appended:  first the errors, then the warnings.
 +Entries are of the form (MSG BEG END)."
 +  (when js2-mode-ast
 +    (append (js2-ast-root-errors js2-mode-ast)
 +            (copy-sequence (js2-ast-root-warnings js2-mode-ast)))))
 +
  (defun js2-next-error (&optional arg reset)
    "Move to next parse error.
  Typically invoked via \\[next-error].

commit 29d8f2f1b8bd3d4dc452060e06ec407b0a6a8cf3
Author: Andrew Hyatt <address@hidden>
Date:   Sun Sep 2 22:20:09 2012 -0400

    Encode all text sent from the websocket-send-text function.
    
    This is necessary for non-ascii text.

diff --git a/websocket-test.el b/websocket-test.el
index 04f14df..c965033 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -400,6 +400,13 @@
          (should-not on-open-calledp)
          (should websocket-closed-calledp))))))
 
+(ert-deftest websocket-send-text ()
+  (flet ((websocket-send (ws frame)
+                         (should (equal
+                                  (websocket-frame-payload frame)
+                                  "\344\275\240\345\245\275"))))
+    (websocket-send-text nil "你好")))
+
 (ert-deftest websocket-send ()
   (let ((ws (websocket-inner-create :conn t :url t :accept-string t)))
     (flet ((websocket-ensure-connected (websocket))
diff --git a/websocket.el b/websocket.el
index 2de93ec..95a7eba 100644
--- a/websocket.el
+++ b/websocket.el
@@ -480,8 +480,12 @@ has connection termination."
 
 (defun websocket-send-text (websocket text)
   "To the WEBSOCKET, send TEXT as a complete frame."
-  (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
-                                                  :completep t)))
+  (websocket-send
+   websocket
+   (make-websocket-frame :opcode 'text
+                         :payload (encode-coding-string
+                                   text 'raw-text)
+                         :completep t)))
 
 (defun websocket-check (frame)
   "Check FRAME for correctness, returning true if correct."

commit 0efcdfe447db605ec188f80ae99caf0a1b48c598
Author: Andrew Hyatt <address@hidden>
Date:   Sun Sep 2 18:57:29 2012 -0400

    Kill processes in the functional test, and make sure that closed
    websocket result in killed processes.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index e9dac95..8183635 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -58,6 +58,12 @@
 (assert (null (websocket-openp wstest-ws)))
 
 (stop-process wstest-server-proc)
+(kill-process wstest-server-proc)
+
+;; Make sure the processes are closed.  This happens asynchronously,
+;; so let's wait for it.
+(sleep-for 1)
+(assert (null (process-list)) t)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Remote server test, with wss ;;
@@ -116,4 +122,8 @@
 (assert (equal (car wstest-msgs) "Hi to self!"))
 (websocket-server-close server-conn)
 (assert wstest-closed)
+(websocket-close wstest-ws)
+
+(sleep-for 1)
+(assert (null (process-list)) t)
 (message "\nAll tests passed!\n")

commit d29b171b812893b30fa0b86eebbaf548518992f9
Author: Andrew Hyatt <address@hidden>
Date:   Sun Sep 2 18:56:40 2012 -0400

    Remove calc requirement, based on observations and suggestions by Julian 
Scheid.

diff --git a/websocket-test.el b/websocket-test.el
index e97da1a..04f14df 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -51,10 +51,11 @@
 (ert-deftest websocket-get-bytes ()
   (should (equal #x5 (websocket-get-bytes "\x5" 1)))
   (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
-  (let ((f (lambda () (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8))))
-    (if websocket-test-64-bit-p
-        (should (equal #x100000001 (funcall f)))
-      (should-error (funcall f) :type 'websocket-unparseable-frame)))
+  (should (equal #xffffff
+                 (websocket-get-bytes "\x0\x0\x0\x0\x0\xFF\xFF\xFF" 8)))
+  (when websocket-test-64-bit-p
+    (should-error (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)
+                  :type 'websocket-unparseable-frame))
   (should-error (websocket-get-bytes "\x0\x0\x0" 3))
   (should-error (websocket-get-bytes "\x0" 2) :type 
'websocket-unparseable-frame))
 
diff --git a/websocket.el b/websocket.el
index 0ec79bf..2de93ec 100644
--- a/websocket.el
+++ b/websocket.el
@@ -47,7 +47,6 @@
 
 (require 'bindat)
 (require 'url-parse)
-(require 'calc)
 (eval-when-compile (require 'cl))
 
 ;;; Code:
@@ -197,16 +196,18 @@ This is based on the KEY from the Sec-WebSocket-Key 
header."
 (defun websocket-get-bytes (s n)
   "From string S, retrieve the value of N bytes.
 Return the value as an unsigned integer.  The value N must be a
-power of 2, up to 8."
+power of 2, up to 8.
+
+We support getting frames up to 4294967295 bytes (2^32) long."
   (if (= n 8)
     (let* ((32-bit-parts
             (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
-           (cval (calc-eval '("(2^32 * $ + $$)") nil
-                            (aref 32-bit-parts 0) (aref 32-bit-parts 1))))
-      (when (calc-eval '("$ > $$") 'pred cval most-positive-fixnum)
+           (cval
+            (logior (lsh (aref 32-bit-parts 0) 32) (aref 32-bit-parts 1))))
+      (if (= (aref 32-bit-parts 0) 0)
+          cval
         (signal 'websocket-unparseable-frame
-                "Frame value found too large to parse!"))
-      (string-to-number cval))
+                "Frame value found too large to parse!")))
     ;; n is not 8
     (bindat-get-field
      (condition-case err
@@ -226,26 +227,23 @@ power of 2, up to 8."
 
 (defun websocket-to-bytes (val nbytes)
   "Encode the integer VAL in NBYTES of data.
-NBYTES much be a power of 2, up to 8."
-  (unless (or (and (< nbytes 8)
-                   (< val (expt 2 (* 8 nbytes))))
-              (and (= nbytes 8)
-                   (calc-eval "% < 2^(8 * %%)" 'pred val nbytes)))
+NBYTES much be a power of 2, up to 8.
+
+This supports encoding values up to "
+  (when (and (< nbytes 8)
+             (> val (expt 2 (* 8 nbytes))))
     ;; not a user-facing error, this must be caused from an error in
     ;; this library
     (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
            val nbytes))
   (if (= nbytes 8)
       (progn
-        (when (calc-eval "$ < 4294967296" 'pred most-positive-fixnum)
-          (signal 'websocket-frame-too-large
-                  most-positive-fixnum))
-        ;; Need to use calc even though at this point things are manageable,
-        ;; since some emacs cannot parse the value 4294967296, even if
-        ;; they never evaluate it.
-        (bindat-pack `((:val vec 2 u32))
-                     `((:val . [,(calc-eval "floor($ / 4294967296)" 'raw val)
-                                ,(calc-eval "$ % 4294967296" 'raw val)]))))
+        (let ((hi-32bits (lsh val -32))
+              (low-32bits (logand #xffffffff val)))
+          (when (> hi-32bits 0)
+            (signal 'websocket-frame-too-large val))
+          (bindat-pack `((:val vec 2 u32))
+                       `((:val . [,hi-32bits ,low-32bits])))))
     (bindat-pack
      `((:val ,(cond ((= nbytes 1) 'u8)
                     ((= nbytes 2) 'u16)
@@ -507,8 +505,8 @@ also the frame.
 
 The frame may be too large for this buid of emacs, in which case
 `websocket-frame-too-large' is returned, with the data of the
-system's `most-positive-fixnum', whose length was exceeded.  This
-also has the `websocket-error' condition."
+size of the frame which was too large to process.  This also has
+the `websocket-error' condition."
   (unless (websocket-check frame)
     (signal 'websocket-illegal-frame frame))
   (websocket-debug websocket "Sending frame, opcode: %s payload: %s"

commit b02f4a0d72d0e2087038fe891e2580c4505415ef
Author: Dmitry Gutov <address@hidden>
Date:   Mon Sep 3 02:29:44 2012 +0400

    Fix infinite timers loop
    
    Refs #49

diff --git a/js2-mode.el b/js2-mode.el
index c7ba811..7a8c744 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10552,9 +10552,12 @@ You can disable this by customizing 
`js2-cleanup-whitespace'."
   (if js2-mode-parse-timer
       (cancel-timer js2-mode-parse-timer))
   (setq js2-mode-parsing nil)
-  (setq js2-mode-parse-timer
-        (run-with-idle-timer js2-idle-timer-delay nil
-                             #'js2-mode-idle-reparse (current-buffer))))
+  (let ((timer (timer-create)))
+    (setq js2-mode-parse-timer timer)
+    (timer-set-function timer 'js2-mode-idle-reparse (list (current-buffer)))
+    (timer-set-idle-time timer js2-idle-timer-delay)
+    ;; http://debbugs.gnu.org/cgi/bugreport.cgi?bug=12326
+    (timer-activate-when-idle timer nil)))
 
 (defun js2-mode-idle-reparse (buffer)
   "Run `js2-reparse' if BUFFER is the current buffer, or schedule

commit 1303cca62f4ea725baf6e2d8c75ddd9578515ac3
Author: Dmitry Gutov <address@hidden>
Date:   Mon Sep 3 02:03:16 2012 +0400

    js2-mode-forward-sexp: When inside "parens", jump over closest child node

diff --git a/js2-mode.el b/js2-mode.el
index 3833e01..c7ba811 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11448,7 +11448,7 @@ move backward across N balanced expressions."
   (when js2-mode-buffer-dirty-p
     (js2-reparse))
   (let ((scan-msg "Containing expression ends prematurely")
-        node (start (point)) pos lp rp)
+        node (start (point)) pos lp rp child)
     (cond
      ;; backward-sexp
      ;; could probably make this better for some cases:
@@ -11464,13 +11464,16 @@ move backward across N balanced expressions."
           (let ((parens (js2-mode-forward-sexp-parens node pos)))
             (setq lp (car parens)
                   rp (cdr parens))))
-        (goto-char (or (when (and lp (> start lp))
-                         (when (and rp (<= start rp))
-                           (goto-char start)
-                           (signal 'scan-error (list scan-msg lp lp)))
-                         lp)
-                       pos
-                       (point-min)))))
+        (goto-char
+         (or (when (and lp (> start lp))
+               (if (and rp (<= start rp))
+                   (if (setq child (js2-node-closest-child node (point) lp t))
+                       (js2-node-abs-pos child)
+                     (goto-char start)
+                     (signal 'scan-error (list scan-msg lp lp)))
+                 lp))
+             pos
+             (point-min)))))
      (t
       ;; forward-sexp
       (js2-forward-sws)
@@ -11481,18 +11484,22 @@ move backward across N balanced expressions."
           (let ((parens (js2-mode-forward-sexp-parens node pos)))
             (setq lp (car parens)
                   rp (cdr parens))))
-        (goto-char (or (when (and rp (<= start rp))
-                         (when (> start lp)
-                           (goto-char start)
-                           (signal 'scan-error (list scan-msg rp (1+ rp))))
-                         (1+ rp))
-                       (+ pos
-                          (js2-node-len
-                           (if (js2-expr-stmt-node-p (js2-node-parent node))
-                               ;; stop after the semicolon
-                               (js2-node-parent node)
-                             node)))
-                       (point-max))))))))
+        (goto-char
+         (or (when (and rp (<= start rp))
+               (if (> start lp)
+                   (if (setq child (js2-node-closest-child node (point) rp))
+                       (js2-node-abs-end child)
+                     (goto-char start)
+                     (signal 'scan-error (list scan-msg rp (1+ rp))))
+                 (1+ rp)))
+             (and pos
+                  (+ pos
+                     (js2-node-len
+                      (if (js2-expr-stmt-node-p (js2-node-parent node))
+                          ;; stop after the semicolon
+                          (js2-node-parent node)
+                        node))))
+             (point-max))))))))
 
 (defun js2-mode-forward-sexp-parens (node abs-pos)
   (cond
@@ -11507,6 +11514,29 @@ move backward across N balanced expressions."
       (cons (when lp (+ abs-pos lp))
             (when rp (+ abs-pos rp)))))))
 
+(defun js2-node-closest-child (parent point limit &optional before)
+  (let* ((parent-pos (js2-node-abs-pos parent))
+         (rpoint (- point parent-pos))
+         (rlimit (- limit parent-pos))
+         (min (min rpoint rlimit))
+         (max (max rpoint rlimit))
+         found)
+    (catch 'done
+      (js2-visit-ast
+       parent
+       (lambda (node end-p)
+         (if (eq node parent)
+             t
+           (let ((pos (js2-node-pos node)) ;; Both relative values.
+                 (end (+ (js2-node-pos node) (js2-node-len node))))
+             (when (and (>= pos min) (<= end max)
+                        (if before (< pos rpoint) (> end rpoint)))
+               (setq found node))
+             (when (> end rpoint)
+               (throw 'done nil)))
+           nil))))
+    found))
+
 (defun js2-next-error (&optional arg reset)
   "Move to next parse error.
 Typically invoked via \\[next-error].

commit f34455fd511bb445306b4e333f2c2845ee4ad96d
Author: Dmitry Gutov <address@hidden>
Date:   Sun Sep 2 22:22:32 2012 +0400

    js2-mode-forward-sexp-parens: if/else and loop bodies are js2-scope nodes

diff --git a/js2-mode.el b/js2-mode.el
index 95e9065..3833e01 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11499,7 +11499,7 @@ move backward across N balanced expressions."
    ((or (js2-array-node-p node)
         (js2-object-node-p node)
         (js2-array-comp-node-p node)
-        (eq 'cl-struct-js2-block-node (aref node 0)))
+        (memq (aref node 0) '(cl-struct-js2-block-node cl-struct-js2-scope)))
     (cons abs-pos (+ abs-pos (js2-node-len node) -1)))
    ((js2-paren-expr-node-p node)
     (let ((lp (js2-node-lp node))

commit f26abe1c150264162676826cd48a8fed87f3ada4
Merge: 95ed2b8 7ea106e
Author: Dmitry Gutov <address@hidden>
Date:   Fri Aug 31 08:18:35 2012 +0400

    Merge branch 'master' into emacs24

diff --cc js2-mode.el
index 5ca1557,95e9065..f72114f
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -10494,11 -10636,13 +10494,12 @@@ buffer will only rebuild its `js2-mode-
          (unless interrupted-p
            (setq js2-mode-parse-timer nil))))))
  
- (defun js2-mode-show-node ()
+ (defun js2-mode-show-node (event)
    "Debugging aid:  highlight selected AST node on mouse click."
-   (interactive)
+   (interactive "e")
+   (mouse-set-point event)
    (let ((node (js2-node-at-point))
 -        beg
 -        end)
 +        beg end)
      (when js2-mode-show-overlay
        (if (null node)
            (message "No node found at location %s" (point))
@@@ -11113,42 -11459,54 +11119,76 @@@ move backward across N balanced express
        (dotimes (i (- arg))
          (js2-backward-sws)
          (forward-char -1)  ; enter the node we backed up to
-         (setq node (js2-node-at-point (point) t))
-         (goto-char (if node
-                        (js2-node-abs-pos node)
-                      (point-min)))))
-     (t
-      ;; forward-sexp
-      (js2-forward-sws)
-      (dotimes (i arg)
-        (js2-forward-sws)
-        (setq node (js2-node-at-point (point) t)
-              end (if node (+ (js2-node-abs-pos node)
-                              (js2-node-len node))))
-        (goto-char (or end (point-max))))))))
+         (when (setq node (js2-node-at-point (point) t))
+           (setq pos (js2-node-abs-pos node))
+           (let ((parens (js2-mode-forward-sexp-parens node pos)))
+             (setq lp (car parens)
+                   rp (cdr parens))))
+         (goto-char (or (when (and lp (> start lp))
+                          (when (and rp (<= start rp))
+                            (goto-char start)
+                            (signal 'scan-error (list scan-msg lp lp)))
+                          lp)
+                        pos
+                        (point-min)))))
+      (t
+       ;; forward-sexp
+       (js2-forward-sws)
+       (dotimes (i arg)
+         (js2-forward-sws)
+         (when (setq node (js2-node-at-point (point) t))
+           (setq pos (js2-node-abs-pos node))
+           (let ((parens (js2-mode-forward-sexp-parens node pos)))
+             (setq lp (car parens)
+                   rp (cdr parens))))
+         (goto-char (or (when (and rp (<= start rp))
+                          (when (> start lp)
+                            (goto-char start)
+                            (signal 'scan-error (list scan-msg rp (1+ rp))))
+                          (1+ rp))
+                        (+ pos
+                           (js2-node-len
+                            (if (js2-expr-stmt-node-p (js2-node-parent node))
+                                ;; stop after the semicolon
+                                (js2-node-parent node)
+                              node)))
+                        (point-max))))))))
+ 
+ (defun js2-mode-forward-sexp-parens (node abs-pos)
+   (cond
+    ((or (js2-array-node-p node)
+         (js2-object-node-p node)
+         (js2-array-comp-node-p node)
+         (eq 'cl-struct-js2-block-node (aref node 0)))
+     (cons abs-pos (+ abs-pos (js2-node-len node) -1)))
+    ((js2-paren-expr-node-p node)
+     (let ((lp (js2-node-lp node))
+           (rp (js2-node-rp node)))
+       (cons (when lp (+ abs-pos lp))
+             (when rp (+ abs-pos rp)))))))
  
 +(defun js2-errors ()
 +  "Return a list of errors found."
 +  (and js2-mode-ast
 +       (js2-ast-root-errors js2-mode-ast)))
 +
 +(defun js2-warnings ()
 +  "Return a list of warnings found."
 +  (and js2-mode-ast
 +       (js2-ast-root-warnings js2-mode-ast)))
 +
 +(defun js2-have-errors-p ()
 +  "Return non-nil if any parse errors or warnings were found."
 +  (or (js2-errors) (js2-warnings)))
 +
 +(defun js2-errors-and-warnings ()
 +  "Return a copy of the concatenated errors and warnings lists.
 +They are appended:  first the errors, then the warnings.
 +Entries are of the form (MSG BEG END)."
 +  (when js2-mode-ast
 +    (append (js2-ast-root-errors js2-mode-ast)
 +            (copy-sequence (js2-ast-root-warnings js2-mode-ast)))))
 +
  (defun js2-next-error (&optional arg reset)
    "Move to next parse error.
  Typically invoked via \\[next-error].

commit 7ea106e70cd528117afb6764662a5832cc0a71f4
Author: Dmitry Gutov <address@hidden>
Date:   Fri Aug 31 07:39:17 2012 +0400

    js2-mode-forward-sexp: Signal scan-error when start == rp

diff --git a/js2-mode.el b/js2-mode.el
index 3f1bbf4..95e9065 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11481,7 +11481,7 @@ move backward across N balanced expressions."
           (let ((parens (js2-mode-forward-sexp-parens node pos)))
             (setq lp (car parens)
                   rp (cdr parens))))
-        (goto-char (or (when (and rp (< start rp))
+        (goto-char (or (when (and rp (<= start rp))
                          (when (> start lp)
                            (goto-char start)
                            (signal 'scan-error (list scan-msg rp (1+ rp))))

commit 99f7a96c3e41f3868923d9278398b573bebfd122
Author: Dmitry Gutov <address@hidden>
Date:   Wed Aug 29 23:33:52 2012 +0400

    js2-mode-forward-sexp: backtrack before signaling scan-error
    
    * Jump past the semicolon when current node's parent is expr-stmt-node.

diff --git a/js2-mode.el b/js2-mode.el
index 59257d2..3f1bbf4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -11483,9 +11483,15 @@ move backward across N balanced expressions."
                   rp (cdr parens))))
         (goto-char (or (when (and rp (< start rp))
                          (when (> start lp)
+                           (goto-char start)
                            (signal 'scan-error (list scan-msg rp (1+ rp))))
                          (1+ rp))
-                       (+ pos (js2-node-len node))
+                       (+ pos
+                          (js2-node-len
+                           (if (js2-expr-stmt-node-p (js2-node-parent node))
+                               ;; stop after the semicolon
+                               (js2-node-parent node)
+                             node)))
                        (point-max))))))))
 
 (defun js2-mode-forward-sexp-parens (node abs-pos)

commit 7f15efe5d93ba80a715150ae9e6a15c7d8b1f085
Author: Dmitry Gutov <address@hidden>
Date:   Wed Aug 29 21:24:47 2012 +0400

    js2-mode-forward-sexp: Behave more similarly to `forward-sexp'
    
    * Stop at node parens
    * Signal scan-error upon reaching a parenthesized expression boundary
    * If the buffer is dirty, reparse it synchronously
    
    This increases compatibility with standard *-list commands, evil-mode paren
    motions, and blink-matching-paren feature.
    
    Close #56
    Close #44
    
    js2-node-rp: Fix for js2-elem-get-node.

diff --git a/js2-mode.el b/js2-mode.el
index e2c2796..59257d2 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4387,7 +4387,7 @@ For `js2-elem-get-node' structs, returns right-bracket 
position.
 Note that the position may be nil in the case of a parse error."
   (cond
    ((js2-elem-get-node-p node)
-    (js2-elem-get-node-lb node))
+    (js2-elem-get-node-rb node))
    ((js2-loop-node-p node)
     (js2-loop-node-rp node))
    ((js2-function-node-p node)
@@ -11445,9 +11445,10 @@ With ARG, do it that many times.  Negative arg -N means
 move backward across N balanced expressions."
   (interactive "p")
   (setq arg (or arg 1))
-  (if js2-mode-buffer-dirty-p
-      (js2-mode-wait-for-parse #'js2-mode-forward-sexp))
-  (let (node end (start (point)))
+  (when js2-mode-buffer-dirty-p
+    (js2-reparse))
+  (let ((scan-msg "Containing expression ends prematurely")
+        node (start (point)) pos lp rp)
     (cond
      ;; backward-sexp
      ;; could probably make this better for some cases:
@@ -11458,19 +11459,47 @@ move backward across N balanced expressions."
       (dotimes (i (- arg))
         (js2-backward-sws)
         (forward-char -1)  ; enter the node we backed up to
-        (setq node (js2-node-at-point (point) t))
-        (goto-char (if node
-                       (js2-node-abs-pos node)
-                     (point-min)))))
-    (t
-     ;; forward-sexp
-     (js2-forward-sws)
-     (dotimes (i arg)
-       (js2-forward-sws)
-       (setq node (js2-node-at-point (point) t)
-             end (if node (+ (js2-node-abs-pos node)
-                             (js2-node-len node))))
-       (goto-char (or end (point-max))))))))
+        (when (setq node (js2-node-at-point (point) t))
+          (setq pos (js2-node-abs-pos node))
+          (let ((parens (js2-mode-forward-sexp-parens node pos)))
+            (setq lp (car parens)
+                  rp (cdr parens))))
+        (goto-char (or (when (and lp (> start lp))
+                         (when (and rp (<= start rp))
+                           (goto-char start)
+                           (signal 'scan-error (list scan-msg lp lp)))
+                         lp)
+                       pos
+                       (point-min)))))
+     (t
+      ;; forward-sexp
+      (js2-forward-sws)
+      (dotimes (i arg)
+        (js2-forward-sws)
+        (when (setq node (js2-node-at-point (point) t))
+          (setq pos (js2-node-abs-pos node))
+          (let ((parens (js2-mode-forward-sexp-parens node pos)))
+            (setq lp (car parens)
+                  rp (cdr parens))))
+        (goto-char (or (when (and rp (< start rp))
+                         (when (> start lp)
+                           (signal 'scan-error (list scan-msg rp (1+ rp))))
+                         (1+ rp))
+                       (+ pos (js2-node-len node))
+                       (point-max))))))))
+
+(defun js2-mode-forward-sexp-parens (node abs-pos)
+  (cond
+   ((or (js2-array-node-p node)
+        (js2-object-node-p node)
+        (js2-array-comp-node-p node)
+        (eq 'cl-struct-js2-block-node (aref node 0)))
+    (cons abs-pos (+ abs-pos (js2-node-len node) -1)))
+   ((js2-paren-expr-node-p node)
+    (let ((lp (js2-node-lp node))
+          (rp (js2-node-rp node)))
+      (cons (when lp (+ abs-pos lp))
+            (when rp (+ abs-pos rp)))))))
 
 (defun js2-next-error (&optional arg reset)
   "Move to next parse error.

commit 36d675fd95dec21602e7b75c4eca3c282b626a29
Author: Takafumi Arakaki <address@hidden>
Date:   Tue Aug 28 09:43:05 2012 +0200

    Add Existing clients: Emacs Realtime Markdown Viewer
    
    Emacs Realtime Markdown Viewer is a Emacs lisp library by @syohex

diff --git a/README.org b/README.org
index a81b8e2..3734b68 100644
--- a/README.org
+++ b/README.org
@@ -36,6 +36,7 @@ Each version that is released should be checked with this 
checklist:
 * Existing clients:
 
 - [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]]
+- [[https://github.com/syohex/emacs-realtime-markdown-viewer][Emacs Realtime 
Markdown Viewer]]
 
 If you are using this module for your own emacs package, please let me
 know by editing this file, adding your project, and sending a pull

commit d8ee6b767476250249522dfa3a746602841af28c
Author: Andrew Hyatt <address@hidden>
Date:   Fri Aug 24 00:38:06 2012 -0400

    Set version to 0.93.1

diff --git a/websocket.el b/websocket.el
index d7d96eb..0ec79bf 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication, Websocket, Server
-;; Version: 0.93
+;; Version: 0.93.1
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -102,7 +102,7 @@ same for the protocols.
   accept-string
   (inflight-input nil))
 
-(defvar websocket-version "0.93"
+(defvar websocket-version "0.93.1"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit a7239526f15989df87dd3a1b86ace42c36254e18
Author: Andrew Hyatt <address@hidden>
Date:   Fri Aug 24 00:35:00 2012 -0400

    Fix issue with inflight-input not being cleared out.

diff --git a/websocket-test.el b/websocket-test.el
index 869ca5b..e97da1a 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -374,7 +374,8 @@
                                        (substring websocket-frames 0 2)))
       (should open-callback-called)
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
-      (should (equal (list frame2 frame1) processed-frames)))
+      (should (equal (list frame2 frame1) processed-frames))
+      (should-not (websocket-inflight-input fake-ws)))
     (flet ((websocket-ready-state (websocket) 'connecting)
            (websocket-close (websocket)))
       (should (eq 500 (cdr (should-error
diff --git a/websocket.el b/websocket.el
index a010fe7..d7d96eb 100644
--- a/websocket.el
+++ b/websocket.el
@@ -689,6 +689,7 @@ connection is invalid, the connection will be closed."
         (end-point 0)
         (text (concat (websocket-inflight-input websocket) output))
         (header-end-pos))
+    (setf (websocket-inflight-input websocket) nil)
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
     (when (and (eq 'connecting (websocket-ready-state websocket))

commit 4878bd1666badf844156b6f983759e4aebb047d0
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 18 22:26:06 2012 -0400

    Change version to version 0.93

diff --git a/websocket.el b/websocket.el
index 3ba8493..a010fe7 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication, Websocket, Server
-;; Version: 0.92.1
+;; Version: 0.93
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -102,7 +102,7 @@ same for the protocols.
   accept-string
   (inflight-input nil))
 
-(defvar websocket-version "0.92.1"
+(defvar websocket-version "0.93"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit 8d31b971122585f477062dbd4d317125acf58945
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 18 22:21:59 2012 -0400

    More fixes for file comments.

diff --git a/websocket.el b/websocket.el
index f8928ee..3ba8493 100644
--- a/websocket.el
+++ b/websocket.el
@@ -1,4 +1,4 @@
-;;; websocket.el --- Emacs WebSocket client
+;;; websocket.el --- Emacs WebSocket client and server
 
 ;; Copyright (c) 2010 Andrew Hyatt
 ;;
@@ -71,7 +71,7 @@ A websocket struct is created with `websocket-open'.
 The W3C API \"bufferedAmount\" call is not currently implemented,
 since there is no elisp API to get the buffered amount from the
 subprocess.  There may, in fact, be output data buffered,
-however, when the `on-message' or `close-callback' callbacks are
+however, when the `on-message' or `on-close' callbacks are
 called.
 
 `on-open', `on-message', `on-close', and `on-error' are described

commit 5c2b2351e6d1b9be40b3ac232bcb20fac5eadf69
Author: Andrew Hyatt <address@hidden>
Date:   Thu Aug 16 00:15:18 2012 -0400

    Implement proper behavior on closing of server.
    
    Now all client connections are closed when websocket-server-close is called.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 2bdd74a..e9dac95 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -91,14 +91,16 @@
 
 (message "Testing with emacs websocket server.")
 (message "If this does not pass, make sure your firewall allows the 
connection.")
-
+(setq wstest-closed nil)
 (setq server-conn (websocket-server
                    9998
                    :on-message (lambda (ws frame)
                                  (message "Server received text!")
                                  (websocket-send-text ws
                                   (websocket-frame-payload frame)))
-                   :on-open (lambda (websocket) "Client connection opened!")))
+                   :on-open (lambda (websocket) "Client connection opened!")
+                   :on-close (lambda (websocket)
+                               (setq wstest-closed t))))
 
 (setq wstest-msgs nil
       wstest-ws
@@ -113,4 +115,5 @@
 (sleep-for 0.3)
 (assert (equal (car wstest-msgs) "Hi to self!"))
 (websocket-server-close server-conn)
+(assert wstest-closed)
 (message "\nAll tests passed!\n")
diff --git a/websocket-test.el b/websocket-test.el
index 23086d7..869ca5b 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -323,18 +323,21 @@
                                                              :completep 
t))))))))
 
 (ert-deftest websocket-close ()
-  (let ((sent-frames))
+  (let ((sent-frames)
+        (processes-deleted))
     (flet ((websocket-send (websocket frame) (push frame sent-frames))
            (websocket-openp (websocket) t)
            (kill-buffer (buffer))
-           (process-buffer (conn)))
+           (delete-process (proc))
+           (process-buffer (conn) (add-to-list 'processes-deleted conn)))
       (websocket-close (websocket-inner-create
                         :conn "fake-conn"
                         :url t
                         :accept-string t))
       (should (equal sent-frames (list
                                   (make-websocket-frame :opcode 'close
-                                                        :completep t)))))))
+                                                        :completep t))))
+      (should (equal processes-deleted '("fake-conn"))))))
 
 (ert-deftest websocket-outer-filter ()
   (let* ((fake-ws (websocket-inner-create
@@ -539,3 +542,31 @@
                         ws
                         (plist-get header-info :protocols)
                         (plist-get header-info :extension)))))))
+
+(ert-deftest websocket-server-close ()
+  (let ((websocket-server-websockets
+         (list (websocket-inner-create :conn 'conn-a :url t :accept-string t
+                                       :server-conn 'a
+                                       :ready-state 'open)
+               (websocket-inner-create :conn 'conn-b :url t :accept-string t
+                                       :server-conn 'b
+                                       :ready-state 'open)
+               (websocket-inner-create :conn 'conn-c :url t :accept-string t
+                                       :server-conn 'b
+                                       :ready-state 'closed)))
+        (deleted-processes)
+        (closed-websockets))
+    (flet ((delete-process (conn) (add-to-list 'deleted-processes conn))
+           (websocket-close (ws)
+                            ;; we always remove on closing in the
+                            ;; actual code.
+                            (setq websocket-server-websockets
+                                  (remove ws websocket-server-websockets))
+                            (should-not (eq (websocket-ready-state ws) 
'closed))
+                            (add-to-list 'closed-websockets ws)))
+      (websocket-server-close 'b))
+    (should (equal deleted-processes '(b)))
+    (should (eq 1 (length closed-websockets)))
+    (should (eq 'conn-b (websocket-conn (car closed-websockets))))
+    (should (eq 1 (length websocket-server-websockets)))
+    (should (eq 'conn-a (websocket-conn (car websocket-server-websockets))))))
diff --git a/websocket.el b/websocket.el
index 3d9b00d..f8928ee 100644
--- a/websocket.el
+++ b/websocket.el
@@ -97,6 +97,8 @@ same for the protocols.
   (protocols nil :read-only t)
   (extensions nil :read-only t)
   (conn (assert nil) :read-only t)
+  ;; Only populated for servers, this is the server connection.
+  server-conn
   accept-string
   (inflight-input nil))
 
@@ -533,9 +535,9 @@ connecting or open."
                     (make-websocket-frame :opcode 'close
                                           :completep t))
     (setf (websocket-ready-state websocket) 'closed))
-  ;; Do we want to kill this?  It may result in on-closed not being
-  ;; called.
-  (kill-buffer (process-buffer (websocket-conn websocket))))
+  (let ((buf (process-buffer (websocket-conn websocket))))
+    (delete-process (websocket-conn websocket))
+    (kill-buffer buf)))
 
 (defun websocket-ensure-connected (websocket)
   "If the WEBSOCKET connection is closed, open it."
@@ -757,6 +759,9 @@ of populating the list of server extensions to WEBSOCKET."
 ;; Websocket server ;;
 ;;;;;;;;;;;;;;;;;;;;;;
 
+(defvar websocket-server-websockets nil
+  "A list of current websockets live on any server.")
+
 (defun* websocket-server (port &rest plist)
   "Open a websocket server on PORT.
 This also takes a plist of callbacks: `:on-open', `:on-message',
@@ -775,28 +780,47 @@ connection, which should be kept in order to pass to
     conn))
 
 (defun websocket-server-close (conn)
-  "Closes the websocket, as well as all open websockets."
-  ;; TODO(ahyatt) Delete all open websockets (we have to start keeping
-  ;; track first)
+  "Closes the websocket, as well as all open websockets for this server."
+  (let ((to-delete))
+    (dolist (ws websocket-server-websockets)
+      (when (eq (websocket-server-conn ws) conn)
+        (if (eq (websocket-ready-state ws) 'closed)
+            (add-to-list 'to-delete ws)
+          (websocket-close ws))))
+    (dolist (ws to-delete)
+      (setq websocket-server-websockets (remove ws 
websocket-server-websockets))))
   (delete-process conn))
 
 (defun websocket-server-accept (server client message)
   "Accept a new websocket connection from a client."
-  (message "Connected from %S: %s" client message)
   (let ((ws (websocket-inner-create
+             :server-conn server
              :conn client
              :url client
              :on-open (or (process-get server :on-open) 'identity)
              :on-message (or (process-get server :on-message) (lambda (ws 
frame)))
+             :on-close (lexical-let ((user-method
+                                      (or (process-get server :on-close) 
'identity)))
+                         (lambda (ws)
+                           (setq websocket-server-websockets
+                                 (remove ws websocket-server-websockets))
+                           (funcall user-method ws)))
              :on-error (or (process-get server :on-error)
                            'websocket-default-error-handler)
              :protocols (process-get server :protocol)
              :extensions (mapcar 'car (process-get server :extensions)))))
+    (add-to-list 'websocket-server-websockets ws)
     (process-put client :websocket ws)
     (set-process-filter client 'websocket-server-filter)
     ;; set-process-filter-multibyte is obsolete, but make-network-process's
     ;; :filter-multibyte arg does not seem to do anything.
-    (set-process-filter-multibyte client nil)))
+    (set-process-filter-multibyte client nil)
+    (set-process-sentinel client
+     (lambda (process change)
+       (let ((websocket (process-get process :websocket)))
+         (websocket-debug websocket "State change to %s" change)
+         (unless (eq 'closed (websocket-ready-state websocket))
+           (websocket-try-callback 'websocket-on-close 'on-close 
websocket)))))))
 
 (defun websocket-create-headers (url key protocol extensions)
   "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS.

commit 23b132e4a7c0eb42bd3ca94a2b0efd92fc6d5979
Author: Andrew Hyatt <address@hidden>
Date:   Tue Aug 14 22:35:46 2012 -0400

    Fix failing ert tests

diff --git a/websocket-test.el b/websocket-test.el
index 9fc6e3b..23086d7 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -202,8 +202,7 @@
         (base-headers (concat "Host: www.example.com\r\n"
                               "Upgrade: websocket\r\n"
                               "Connection: Upgrade\r\n"
-                              (format "Sec-WebSocket-Key: %s\r\n"
-                                      (websocket-calculate-accept "key"))
+                              "Sec-WebSocket-Key: key\r\n"
                               "Origin: mysystem\r\n"
                               "Sec-WebSocket-Version: 13\r\n")))
     (should (equal (concat base-headers "\r\n")
@@ -419,7 +418,7 @@
   (let* ((http "HTTP/1.1")
          (host "Host: authority")
          (upgrade "Upgrade: websocket")
-         (key (format "Sec-Websocket-Key: %s" (base64-encode-string "key")))
+         (key (format "Sec-Websocket-Key: %s" "key"))
          (version "Sec-Websocket-Version: 13")
          (origin "Origin: origin")
          (protocol "Sec-Websocket-Protocol: protocol")
@@ -487,7 +486,7 @@
            (websocket-close (ws) (setq closed t))
            (process-get (process sym) ws))
      ;; Bad request, in two parts
-     (flet ((websocket-verify-client-headers (ws text) nil))
+     (flet ((websocket-verify-client-headers (text) nil))
        (websocket-server-filter nil "HTTP/1.0 GET /foo \r\n")
        (should-not closed)
        (websocket-server-filter nil "\r\n")
@@ -497,7 +496,7 @@
      (setq closed nil
            response nil)
      (setf (websocket-inflight-input ws) nil)
-     (flet ((websocket-verify-client-headers (ws text) t)
+     (flet ((websocket-verify-client-headers (text) t)
             (websocket-get-server-response (ws protocols extensions)
                                            "response")
             (websocket-process-input-on-open-ws (ws text)

commit 22b032250265857d0e6e1f90ebb6db0124180cbf
Author: Andrew Hyatt <address@hidden>
Date:   Tue Aug 14 22:35:39 2012 -0400

    Fix up documentation to refer to server functionality.

diff --git a/README.org b/README.org
index b9c879a..a81b8e2 100644
--- a/README.org
+++ b/README.org
@@ -1,7 +1,9 @@
 * Description
 This is a elisp library for websocket clients to talk to websocket
-servers. This library is designed to be used by other library writers,
-to write apps that use websockets, and is not useful by itself.
+servers, and for websocket servers to accept connections from
+websocket clients. This library is designed to be used by other
+library writers, to write apps that use websockets, and is not useful
+by itself.
 
 An example of how to use the library is in the
 
[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]]
 file.
@@ -27,7 +29,9 @@ Each version that is released should be checked with this 
checklist:
 
 - [ ] All ert test passing
 - [ ] Functional test passing on emacs 23 and 24
-- [ ] websocket.el byte compiling cleanly
+- [ ] websocket.el byte compiling cleanly, except for these exceptions:
+  - =set-process-filter-multibyte= is obsolete, yet I cannot find any
+    other way of ensuring my filter has multibyte disabled.
 
 * Existing clients:
 
diff --git a/websocket.el b/websocket.el
index 01e46e4..3d9b00d 100644
--- a/websocket.el
+++ b/websocket.el
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
-;; Keywords: Communication
+;; Keywords: Communication, Websocket, Server
 ;; Version: 0.92.1
 ;;
 ;; This program is free software; you can redistribute it and/or
@@ -26,14 +26,24 @@
 ;; This implements RFC 6455, which can be found at
 ;; http://tools.ietf.org/html/rfc6455.
 ;;
-;; Websockets are created by calling `websocket-open', which returns a
-;; `websocket' struct.  Users of this library use the websocket
-;; struct, and can call methods `websocket-send-text', which sends
-;; text over the websocket, or `websocket-send', which sends a
+;; This library contains code to connect emacs as a client to a
+;; websocket server, and for emacs to act as a server for websocket
+;; connections.
+;;
+;; Websockets clients are created by calling `websocket-open', which
+;; returns a `websocket' struct.  Users of this library use the
+;; websocket struct, and can call methods `websocket-send-text', which
+;; sends text over the websocket, or `websocket-send', which sends a
 ;; `websocket-frame' struct, enabling finer control of what is sent.
 ;; A callback is passed to `websocket-open' that will retrieve
 ;; websocket frames called from the websocket.  Websockets are
 ;; eventually closed with `websocket-close'.
+;;
+;; Server functionality is similar.  A server is started with
+;; `websocket-server' called with a port and the callbacks to use,
+;; which returns a process.  The process can later be closed with
+;; `websocket-server-close'.  A `websocket' struct is also created
+;; for every connection, and is exposed through the callbacks.
 
 (require 'bindat)
 (require 'url-parse)
@@ -417,7 +427,7 @@ if not."
   (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
   (unless (equal "101" (match-string 1 output))
        (signal 'websocket-received-error-http-response
-               (string-to-int (match-string 1 output))))
+               (string-to-number (match-string 1 output))))
   t)
 
 (defun websocket-parse-repeated-field (output field)
@@ -749,8 +759,11 @@ of populating the list of server extensions to WEBSOCKET."
 
 (defun* websocket-server (port &rest plist)
   "Open a websocket server on PORT.
-PORT can be `t' to get a random port.
-TODO(ahyatt): Find out how to return the port number."
+This also takes a plist of callbacks: `:on-open', `:on-message',
+`:on-close' and `:on-error', which operate exactly as documented
+in the websocket client function `websocket-open'.  Returns the
+connection, which should be kept in order to pass to
+`websocket-server-close'."
   (let* ((conn (make-network-process
                 :name (format "websocket server on port %d" port)
                 :server t

commit 8797b3632854703d65010764821a7a81c8d4ca24
Author: Andrew Hyatt <address@hidden>
Date:   Tue Aug 14 22:13:22 2012 -0400

    Modify functional test to fix errors and adjust timing.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 08d8f86..2bdd74a 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -81,7 +81,7 @@
   (assert (websocket-openp wstest-ws))
   (assert (null wstest-msgs))
   (websocket-send-text wstest-ws "Hi!")
-  (sleep-for 0.1)
+  (sleep-for 0.3)
   (assert (equal (car wstest-msgs) "Hi!"))
   (websocket-close wstest-ws))
 
@@ -96,9 +96,10 @@
                    9998
                    :on-message (lambda (ws frame)
                                  (message "Server received text!")
-                                 (websocket-send-text
+                                 (websocket-send-text ws
                                   (websocket-frame-payload frame)))
                    :on-open (lambda (websocket) "Client connection opened!")))
+
 (setq wstest-msgs nil
       wstest-ws
       (websocket-open
@@ -106,8 +107,10 @@
        :on-message (lambda (websocket frame)
                      (push (websocket-frame-payload frame) wstest-msgs)
                      (message "ws frame: %S" (websocket-frame-payload 
frame)))))
+
 (assert (websocket-openp wstest-ws))
 (websocket-send-text wstest-ws "Hi to self!")
+(sleep-for 0.3)
 (assert (equal (car wstest-msgs) "Hi to self!"))
 (websocket-server-close server-conn)
 (message "\nAll tests passed!\n")

commit f2b9aa57779dbb70b25f2541216d25ae0b24cd3b
Author: Andrew Hyatt <address@hidden>
Date:   Mon Aug 13 23:34:29 2012 -0400

    Add functional test for the server, and fix a variety of new bugs.
    
    Currently, my functional tests do not pass, but this may be because of
    firewall issues.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index bcd7468..08d8f86 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -60,7 +60,7 @@
 (stop-process wstest-server-proc)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Remove server test, with wss ;;
+;; Remote server test, with wss ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (when (>= (string-to-int (substring emacs-version 0 2)) 24)
@@ -83,8 +83,31 @@
   (websocket-send-text wstest-ws "Hi!")
   (sleep-for 0.1)
   (assert (equal (car wstest-msgs) "Hi!"))
-  (websocket-close wstest-ws)
-  
-  (message "\nAll tests passed!\n"))
-
-
+  (websocket-close wstest-ws))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Local client and server ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(message "Testing with emacs websocket server.")
+(message "If this does not pass, make sure your firewall allows the 
connection.")
+
+(setq server-conn (websocket-server
+                   9998
+                   :on-message (lambda (ws frame)
+                                 (message "Server received text!")
+                                 (websocket-send-text
+                                  (websocket-frame-payload frame)))
+                   :on-open (lambda (websocket) "Client connection opened!")))
+(setq wstest-msgs nil
+      wstest-ws
+      (websocket-open
+       "ws://localhost:9998"
+       :on-message (lambda (websocket frame)
+                     (push (websocket-frame-payload frame) wstest-msgs)
+                     (message "ws frame: %S" (websocket-frame-payload 
frame)))))
+(assert (websocket-openp wstest-ws))
+(websocket-send-text wstest-ws "Hi to self!")
+(assert (equal (car wstest-msgs) "Hi to self!"))
+(websocket-server-close server-conn)
+(message "\nAll tests passed!\n")
diff --git a/websocket.el b/websocket.el
index 03441a0..01e46e4 100644
--- a/websocket.el
+++ b/websocket.el
@@ -663,7 +663,7 @@ describing the problem with the frame.
     (websocket-debug websocket "Sending handshake, key: %s, acceptance: %s"
                      key (websocket-accept-string websocket))
     (process-send-string conn
-                         (websocket-create-headers url key protocol 
extensions))
+                         (websocket-create-headers url key protocols 
extensions))
     (websocket-debug websocket "Websocket opened")
     websocket))
 
@@ -749,7 +749,8 @@ of populating the list of server extensions to WEBSOCKET."
 
 (defun* websocket-server (port &rest plist)
   "Open a websocket server on PORT.
-PORT can be `t' to get a random port."
+PORT can be `t' to get a random port.
+TODO(ahyatt): Find out how to return the port number."
   (let* ((conn (make-network-process
                 :name (format "websocket server on port %d" port)
                 :server t
@@ -757,22 +758,14 @@ PORT can be `t' to get a random port."
                 :log 'websocket-server-accept
                 :filter-multibyte nil
                 :plist plist
-                :host 'local
-                :service port
-                :local (websocket-get-address port))))))
-
-(defun websocket-get-address (port)
-  "Get a non-loopback address to serve from."
-  (let ((net-addr
-         (block 'get-address
-           (dolist (interface (network-interface-list))
-             (when (not (member
-                         'loopback
-                         (nth 4 (network-interface-info (car interface)))))
-               (return-from 'get-address (cdr interface))))
-           (error "No non-loopback interface found"))))
-    (aset net-addr 4 port)
-    net-addr))
+                :service port)))
+    conn))
+
+(defun websocket-server-close (conn)
+  "Closes the websocket, as well as all open websockets."
+  ;; TODO(ahyatt) Delete all open websockets (we have to start keeping
+  ;; track first)
+  (delete-process conn))
 
 (defun websocket-server-accept (server client message)
   "Accept a new websocket connection from a client."
@@ -782,7 +775,8 @@ PORT can be `t' to get a random port."
              :url client
              :on-open (or (process-get server :on-open) 'identity)
              :on-message (or (process-get server :on-message) (lambda (ws 
frame)))
-             :on-error (or (process-get server :on-error) 'identity)
+             :on-error (or (process-get server :on-error)
+                           'websocket-default-error-handler)
              :protocols (process-get server :protocol)
              :extensions (mapcar 'car (process-get server :extensions)))))
     (process-put client :websocket ws)

commit 4ac8fceb9b3f4fa2453d4a77a3f66de6a6f9bd69
Author: Andrew Hyatt <address@hidden>
Date:   Mon Aug 13 00:38:09 2012 -0400

    Move functions around so that things are easier to find.
    
    Maybe these will eventually be split up into different files, but for
    now that seems like overkill.

diff --git a/websocket.el b/websocket.el
index 1974761..03441a0 100644
--- a/websocket.el
+++ b/websocket.el
@@ -41,6 +41,7 @@
 (eval-when-compile (require 'cl))
 
 ;;; Code:
+
 (defstruct (websocket
             (:constructor nil)
             (:constructor websocket-inner-create))
@@ -382,6 +383,169 @@ the frame finishes.  If the frame is not completed, 
return NIL."
 (put 'websocket-frame-too-large 'error-message
      "The frame being sent is too large for this emacs to handle")
 
+(defun websocket-intersect (a b)
+  "Simple list intersection, should function like common lisp's 
`intersection'."
+  (let ((result))
+    (dolist (elem a (nreverse result))
+      (when (member elem b)
+        (add-to-list 'result elem)))))
+
+(defun websocket-get-debug-buffer-create (websocket)
+  "Get or create the buffer corresponding to WEBSOCKET."
+  (let ((buf (get-buffer-create (format "*websocket %s debug*"
+                                    (websocket-url websocket)))))
+    (when (= 0 (buffer-size buf))
+      (buffer-disable-undo buf))
+    buf))
+
+(defun websocket-debug (websocket msg &rest args)
+  "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
+  (when websocket-debug
+    (let ((buf (websocket-get-debug-buffer-create websocket)))
+      (save-excursion
+        (with-current-buffer buf
+          (goto-char (point-max))
+          (insert "[WS] ")
+          (insert (apply 'format (append (list msg) args)))
+          (insert "\n"))))))
+
+(defun websocket-verify-response-code (output)
+  "Verify that OUTPUT contains a valid HTTP response code.
+The only acceptable one to websocket is responce code 101.
+A t value will be returned on success, and an error thrown
+if not."
+  (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
+  (unless (equal "101" (match-string 1 output))
+       (signal 'websocket-received-error-http-response
+               (string-to-int (match-string 1 output))))
+  t)
+
+(defun websocket-parse-repeated-field (output field)
+  "From header-containing OUTPUT, parse out the list from a
+possibly repeated field."
+  (let ((pos 0)
+        (extensions))
+    (while (and pos
+                (string-match (format "\r\n%s: \\(.*\\)\r\n" field)
+                              output pos))
+      (when (setq pos (match-end 1))
+        (setq extensions (append extensions (split-string
+                                             (match-string 1 output) ", ?")))))
+    extensions))
+
+(defun websocket-process-frame (websocket frame)
+  "Using the WEBSOCKET's filter and connection, process the FRAME.
+This returns a lambda that should be executed when all frames have
+been processed.  If the frame has a payload, the lambda has the frame
+passed to the filter slot of WEBSOCKET.  If the frame is a ping,
+the lambda has a reply with a pong.  If the frame is a close, the lambda
+has connection termination."
+  (let ((opcode (websocket-frame-opcode frame)))
+    (lexical-let ((lex-ws websocket)
+                  (lex-frame frame))
+      (cond ((memq opcode '(continuation text binary))
+             (lambda () (websocket-try-callback 'websocket-on-message 
'on-message
+                                           lex-ws lex-frame)))
+            ((eq opcode 'ping)
+             (lambda () (websocket-send lex-ws
+                                   (make-websocket-frame :opcode 'pong 
:completep t))))
+            ((eq opcode 'close)
+             (lambda () (delete-process (websocket-conn lex-ws))))
+            (t (lambda ()))))))
+
+(defun websocket-process-input-on-open-ws (websocket text)
+  "This handles input processing for both the client and server filters."
+  (let ((current-frame)
+        (processing-queue)
+        (start-point 0))
+    (while (setq current-frame (websocket-read-frame
+                                (substring text start-point)))
+      (push (websocket-process-frame websocket current-frame) processing-queue)
+      (incf start-point (websocket-frame-length current-frame)))
+    (when (> (length text) start-point)
+      (setf (websocket-inflight-input websocket)
+            (substring text start-point)))
+    (dolist (to-process (nreverse processing-queue))
+      (funcall to-process))))
+
+(defun websocket-send-text (websocket text)
+  "To the WEBSOCKET, send TEXT as a complete frame."
+  (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
+                                                  :completep t)))
+
+(defun websocket-check (frame)
+  "Check FRAME for correctness, returning true if correct."
+  (and (equal (not (memq (websocket-frame-opcode frame)
+                         '(continuation text binary)))
+              (and (not (websocket-frame-payload frame))
+                   (websocket-frame-completep frame)))))
+
+(defun websocket-send (websocket frame)
+  "To the WEBSOCKET server, send the FRAME.
+This will raise an error if the frame is illegal.
+
+The error signaled may be of type `websocket-illegal-frame' if
+the frame is malformed in some way, also having the condition
+type of `websocket-error'.  The data associated with the signal
+is the frame being sent.
+
+If the websocket is closed a signal `websocket-closed' is sent,
+also with `websocket-error' condition.  The data in the signal is
+also the frame.
+
+The frame may be too large for this buid of emacs, in which case
+`websocket-frame-too-large' is returned, with the data of the
+system's `most-positive-fixnum', whose length was exceeded.  This
+also has the `websocket-error' condition."
+  (unless (websocket-check frame)
+    (signal 'websocket-illegal-frame frame))
+  (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
+                   (websocket-frame-opcode frame)
+                   (websocket-frame-payload frame))
+  (websocket-ensure-connected websocket)
+  (unless (websocket-openp websocket)
+    (signal 'websocket-closed frame))
+  (process-send-string (websocket-conn websocket)
+                       (websocket-encode-frame frame)))
+
+(defun websocket-openp (websocket)
+  "Check WEBSOCKET and return non-nil if it is open, and either
+connecting or open."
+  (and websocket
+       (not (eq 'close (websocket-ready-state websocket)))
+       (member (process-status (websocket-conn websocket)) '(open run))))
+
+(defun websocket-close (websocket)
+  "Close WEBSOCKET and erase all the old websocket data."
+  (websocket-debug websocket "Closing websocket")
+  (when (websocket-openp websocket)
+    (websocket-send websocket
+                    (make-websocket-frame :opcode 'close
+                                          :completep t))
+    (setf (websocket-ready-state websocket) 'closed))
+  ;; Do we want to kill this?  It may result in on-closed not being
+  ;; called.
+  (kill-buffer (process-buffer (websocket-conn websocket))))
+
+(defun websocket-ensure-connected (websocket)
+  "If the WEBSOCKET connection is closed, open it."
+  (unless (and (websocket-conn websocket)
+               (ecase (process-status (websocket-conn websocket))
+                 ((run open listen) t)
+                 ((stop exit signal closed connect failed nil) nil)))
+    (websocket-close websocket)
+    (websocket-open (websocket-url websocket)
+                    :protocols (websocket-protocols websocket)
+                    :extensions (websocket-extensions websocket)
+                    :on-open (websocket-on-open websocket)
+                    :on-message (websocket-on-message websocket)
+                    :on-close (websocket-on-close websocket)
+                    :on-error (websocket-on-error websocket))))
+
+;;;;;;;;;;;;;;;;;;;;;;
+;; Websocket client ;;
+;;;;;;;;;;;;;;;;;;;;;;
+
 (defun* websocket-open (url &key protocols extensions (on-open 'identity)
                             (on-message (lambda (w f))) (on-close 'identity)
                             (on-error 'websocket-default-error-handler))
@@ -503,6 +667,100 @@ describing the problem with the frame.
     (websocket-debug websocket "Websocket opened")
     websocket))
 
+(defun websocket-outer-filter (websocket output)
+  "Filter the WEBSOCKET server's OUTPUT.
+This will parse headers and process frames repeatedly until there
+is no more output or the connection closes.  If the websocket
+connection is invalid, the connection will be closed."
+  (websocket-debug websocket "Received: %s" output)
+  (let ((start-point)
+        (end-point 0)
+        (text (concat (websocket-inflight-input websocket) output))
+        (header-end-pos))
+    ;; If we've received the complete header, check to see if we've
+    ;; received the desired handshake.
+    (when (and (eq 'connecting (websocket-ready-state websocket))
+               (setq header-end-pos (string-match "\r\n\r\n" text))
+               (setq start-point (+ 4 header-end-pos)))
+      (condition-case err
+          (progn
+            (websocket-verify-response-code text)
+            (websocket-verify-headers websocket text))
+        (error
+         (websocket-close websocket)
+         (signal (car err) (cdr err))))
+      (setf (websocket-ready-state websocket) 'open)
+      (websocket-try-callback 'websocket-on-open 'on-open websocket))
+    (when (eq 'open (websocket-ready-state websocket))
+      (websocket-process-input-on-open-ws
+       websocket (substring text (or start-point 0))))))
+
+(defun websocket-verify-headers (websocket output)
+  "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
+The output is assumed to have complete headers.  This function
+will either return t or call `error'.  This has the side-effect
+of populating the list of server extensions to WEBSOCKET."
+  (let ((accept-string
+         (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
+    (websocket-debug websocket "Checking for accept header: %s" accept-string)
+    (unless (string-match (regexp-quote accept-string) output)
+      (signal 'websocket-invalid-header
+              "Incorrect handshake from websocket: is this really a websocket 
connection?")))
+  (let ((case-fold-search t))
+    (websocket-debug websocket "Checking for upgrade header")
+    (unless (string-match "\r\nUpgrade: websocket\r\n" output)
+      (signal 'websocket-invalid-header
+              "No 'Upgrade: websocket' header found"))
+    (websocket-debug websocket "Checking for connection header")
+    (unless (string-match "\r\nConnection: upgrade\r\n" output)
+      (signal 'websocket-invalid-header
+              "No 'Connection: upgrade' header found"))
+    (when (websocket-protocols websocket)
+      (dolist (protocol (websocket-protocols websocket))
+        (websocket-debug websocket "Checking for protocol match: %s"
+                         protocol)
+        (let ((protocols))
+          (if (string-match
+               (format "\r\nSec-Websocket-Protocol: %s\r\n"
+                       protocol) output)
+              (add-to-list 'protocols protocol)
+            (signal 'websocket-invalid-header
+                    "Incorrect or missing protocol returned by the server."))
+          (setf (websocket-negotiated-protocols websocket) protocols))))
+    (let* ((extensions (websocket-parse-repeated-field
+                        output
+                        "Sec-WebSocket-Extensions"))
+           (extra-extensions))
+      (dolist (ext extensions)
+        (when (not (member
+                    (first (split-string ext "; ?"))
+                    (websocket-extensions websocket)))
+          (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
+      (when extra-extensions
+        (signal 'websocket-invalid-header
+                (format "Non-requested extensions returned by server: %S"
+                        extra-extensions)))
+      (setf (websocket-negotiated-extensions websocket) extensions)))
+  t)
+
+;;;;;;;;;;;;;;;;;;;;;;
+;; Websocket server ;;
+;;;;;;;;;;;;;;;;;;;;;;
+
+(defun* websocket-server (port &rest plist)
+  "Open a websocket server on PORT.
+PORT can be `t' to get a random port."
+  (let* ((conn (make-network-process
+                :name (format "websocket server on port %d" port)
+                :server t
+                :family 'ipv4
+                :log 'websocket-server-accept
+                :filter-multibyte nil
+                :plist plist
+                :host 'local
+                :service port
+                :local (websocket-get-address port))))))
+
 (defun websocket-get-address (port)
   "Get a non-loopback address to serve from."
   (let ((net-addr
@@ -533,40 +791,63 @@ describing the problem with the frame.
     ;; :filter-multibyte arg does not seem to do anything.
     (set-process-filter-multibyte client nil)))
 
-(defun websocket-verify-client-headers (output)
-  "Verify the headers from the WEBSOCKET client connection in OUTPUT.
-Unlike `websocket-verify-headers', this is a quieter routine.  We
-don't want to error due to a bad client, so we just print out
-messages and a plist containing `:key', the websocket key,
-`:protocols' and `:extensions'."
-  (block nil
-    (let ((case-fold-search t)
-          (plist))
-      (unless (string-match "HTTP/1.1" output)
-        (message "Websocket client connection: HTTP/1.1 not found")
-        (return nil))
-      (unless (string-match "^Host: " output)
-        (message "Websocket client connection: Host header not found")
-        (return nil))
-      (unless (string-match "^Upgrade: websocket\r\n" output)
-        (message "Websocket client connection: Upgrade: websocket not found")
-        (return nil))
-      (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output)
-          (setq plist (plist-put plist :key (match-string 1 output)))
-        (message "Websocket client connect: No key sent")
-        (return nil))
-      (unless (string-match "^Sec-WebSocket-Version: 13" output)
-        (message "Websocket client connect: Websocket version 13 not found")
-        (return nil))
-      (when (string-match "^Sec-WebSocket-Protocol:" output)
-        (setq plist (plist-put plist :protocols (websocket-parse-repeated-field
-                                                 output
-                                                 "Sec-Websocket-Protocol"))))
-      (when (string-match "^Sec-WebSocket-Extensions:" output)
-        (setq plist (plist-put plist :extensions 
(websocket-parse-repeated-field
-                                                  output
-                                                  
"Sec-Websocket-Extensions"))))
-      plist)))
+(defun websocket-create-headers (url key protocol extensions)
+  "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS.
+These are defined as in `websocket-open'."
+  (format (concat "Host: %s\r\n"
+                  "Upgrade: websocket\r\n"
+                  "Connection: Upgrade\r\n"
+                  "Sec-WebSocket-Key: %s\r\n"
+                  "Origin: %s\r\n"
+                  "Sec-WebSocket-Version: 13\r\n"
+                  (when protocol
+                    (concat
+                     (mapconcat (lambda (protocol)
+                                  (format "Sec-WebSocket-Protocol: %s" 
protocol))
+                                protocol "\r\n")
+                     "\r\n"))
+                  (when extensions
+                    (format "Sec-WebSocket-Extensions: %s\r\n"
+                            (mapconcat
+                             (lambda (ext)
+                               (concat (car ext)
+                                       (when (cdr ext) "; ")
+                                       (when (cdr ext)
+                                         (mapconcat 'identity (cdr ext) "; 
"))))
+                             extensions ", ")))
+                  "\r\n")
+          (url-host (url-generic-parse-url url))
+          key
+          system-name
+          protocol))
+
+(defun websocket-get-server-response (websocket client-protocols 
client-extensions)
+  "Get the websocket response from client WEBSOCKET."
+  (let ((separator "\r\n"))
+      (concat "HTTP/1.1 101 Switching Protocols" separator
+              "Upgrade: websocket" separator
+              "Connection: Upgrade" separator
+              "Sec-WebSocket-Accept: "
+              (websocket-accept-string websocket) separator
+              (let ((protocols
+                         (websocket-intersect client-protocols
+                                              (websocket-protocols 
websocket))))
+                    (when protocols
+                      (concat
+                       (mapconcat
+                        (lambda (protocol) (format "Sec-WebSocket-Protocol: %s"
+                                              protocol)) protocols separator)
+                       separator)))
+              (let ((extensions (websocket-intersect
+                                   client-extensions
+                                   (websocket-extensions websocket))))
+                  (when extensions
+                    (concat
+                     (mapconcat
+                      (lambda (extension) (format "Sec-Websocket-Extensions: 
%s"
+                                             extension)) extensions separator)
+                     separator)))
+              separator)))
 
 (defun websocket-server-filter (process output)
   "This acts on all OUTPUT from websocket clients PROCESS."
@@ -606,312 +887,40 @@ messages and a plist containing `:key', the websocket 
key,
           ((eq (websocket-ready-state ws) 'closed)
            (message "WARNING: Should not have received further input on closed 
websocket")))))
 
-(defun websocket-intersect (a b)
-  "Simple list intersection, should function like common lisp's 
`intersection'."
-  (let ((result))
-    (dolist (elem a (nreverse result))
-      (when (member elem b)
-        (add-to-list 'result elem)))))
-
-(defun websocket-get-server-response (websocket client-protocols 
client-extensions)
-  "Get the websocket response from client WEBSOCKET."
-  (let ((separator "\r\n"))
-      (concat "HTTP/1.1 101 Switching Protocols" separator
-              "Upgrade: websocket" separator
-              "Connection: Upgrade" separator
-              "Sec-WebSocket-Accept: "
-              (websocket-accept-string websocket) separator
-              (let ((protocols
-                         (websocket-intersect client-protocols
-                                              (websocket-protocols 
websocket))))
-                    (when protocols
-                      (concat
-                       (mapconcat
-                        (lambda (protocol) (format "Sec-WebSocket-Protocol: %s"
-                                              protocol)) protocols separator)
-                       separator)))
-              (let ((extensions (websocket-intersect
-                                   client-extensions
-                                   (websocket-extensions websocket))))
-                  (when extensions
-                    (concat
-                     (mapconcat
-                      (lambda (extension) (format "Sec-Websocket-Extensions: 
%s"
-                                             extension)) extensions separator)
-                     separator)))
-              separator)))
-
-(defun* websocket-server (port &rest plist)
-  "Open a websocket server on PORT.
-PORT can be `t' to get a random port."
-  (let* ((conn (make-network-process
-                :name (format "websocket server on port %d" port)
-                :server t
-                :family 'ipv4
-                :log 'websocket-server-accept
-                :filter-multibyte nil
-                :plist plist
-                :host 'local
-                :service port
-                :local (websocket-get-address port))))))
-
-(defun websocket-create-headers (url key protocol extensions)
-  "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS.
-These are defined as in `websocket-open'."
-  (format (concat "Host: %s\r\n"
-                  "Upgrade: websocket\r\n"
-                  "Connection: Upgrade\r\n"
-                  "Sec-WebSocket-Key: %s\r\n"
-                  "Origin: %s\r\n"
-                  "Sec-WebSocket-Version: 13\r\n"
-                  (when protocol
-                    (concat
-                     (mapconcat (lambda (protocol)
-                                  (format "Sec-WebSocket-Protocol: %s" 
protocol))
-                                protocol "\r\n")
-                     "\r\n"))
-                  (when extensions
-                    (format "Sec-WebSocket-Extensions: %s\r\n"
-                            (mapconcat
-                             (lambda (ext)
-                               (concat (car ext)
-                                       (when (cdr ext) "; ")
-                                       (when (cdr ext)
-                                         (mapconcat 'identity (cdr ext) "; 
"))))
-                             extensions ", ")))
-                  "\r\n")
-          (url-host (url-generic-parse-url url))
-          key
-          system-name
-          protocol))
-
-(defun websocket-get-debug-buffer-create (websocket)
-  "Get or create the buffer corresponding to WEBSOCKET."
-  (let ((buf (get-buffer-create (format "*websocket %s debug*"
-                                    (websocket-url websocket)))))
-    (when (= 0 (buffer-size buf))
-      (buffer-disable-undo buf))
-    buf))
-
-(defun websocket-debug (websocket msg &rest args)
-  "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
-  (when websocket-debug
-    (let ((buf (websocket-get-debug-buffer-create websocket)))
-      (save-excursion
-        (with-current-buffer buf
-          (goto-char (point-max))
-          (insert "[WS] ")
-          (insert (apply 'format (append (list msg) args)))
-          (insert "\n"))))))
-
-(defun websocket-verify-response-code (output)
-  "Verify that OUTPUT contains a valid HTTP response code.
-The only acceptable one to websocket is responce code 101.
-A t value will be returned on success, and an error thrown
-if not."
-  (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
-  (unless (equal "101" (match-string 1 output))
-       (signal 'websocket-received-error-http-response
-               (string-to-int (match-string 1 output))))
-  t)
-
-(defun websocket-parse-repeated-field (output field)
-  "From header-containing OUTPUT, parse out the list from a
-possibly repeated field."
-  (let ((pos 0)
-        (extensions))
-    (while (and pos
-                (string-match (format "\r\n%s: \\(.*\\)\r\n" field)
-                              output pos))
-      (when (setq pos (match-end 1))
-        (setq extensions (append extensions (split-string
-                                             (match-string 1 output) ", ?")))))
-    extensions))
-
-(defun websocket-verify-headers (websocket output)
-  "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
-The output is assumed to have complete headers.  This function
-will either return t or call `error'.  This has the side-effect
-of populating the list of server extensions to WEBSOCKET."
-  (let ((accept-string
-         (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
-    (websocket-debug websocket "Checking for accept header: %s" accept-string)
-    (unless (string-match (regexp-quote accept-string) output)
-      (signal 'websocket-invalid-header
-              "Incorrect handshake from websocket: is this really a websocket 
connection?")))
-  (let ((case-fold-search t))
-    (websocket-debug websocket "Checking for upgrade header")
-    (unless (string-match "\r\nUpgrade: websocket\r\n" output)
-      (signal 'websocket-invalid-header
-              "No 'Upgrade: websocket' header found"))
-    (websocket-debug websocket "Checking for connection header")
-    (unless (string-match "\r\nConnection: upgrade\r\n" output)
-      (signal 'websocket-invalid-header
-              "No 'Connection: upgrade' header found"))
-    (when (websocket-protocols websocket)
-      (dolist (protocol (websocket-protocols websocket))
-        (websocket-debug websocket "Checking for protocol match: %s"
-                         protocol)
-        (let ((protocols))
-          (if (string-match
-               (format "\r\nSec-Websocket-Protocol: %s\r\n"
-                       protocol) output)
-              (add-to-list 'protocols protocol)
-            (signal 'websocket-invalid-header
-                    "Incorrect or missing protocol returned by the server."))
-          (setf (websocket-negotiated-protocols websocket) protocols))))
-    (let* ((extensions (websocket-parse-repeated-field
-                        output
-                        "Sec-WebSocket-Extensions"))
-           (extra-extensions))
-      (dolist (ext extensions)
-        (when (not (member
-                    (first (split-string ext "; ?"))
-                    (websocket-extensions websocket)))
-          (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
-      (when extra-extensions
-        (signal 'websocket-invalid-header
-                (format "Non-requested extensions returned by server: %S"
-                        extra-extensions)))
-      (setf (websocket-negotiated-extensions websocket) extensions)))
-  t)
-
-(defun websocket-process-frame (websocket frame)
-  "Using the WEBSOCKET's filter and connection, process the FRAME.
-This returns a lambda that should be executed when all frames have
-been processed.  If the frame has a payload, the lambda has the frame
-passed to the filter slot of WEBSOCKET.  If the frame is a ping,
-the lambda has a reply with a pong.  If the frame is a close, the lambda
-has connection termination."
-  (let ((opcode (websocket-frame-opcode frame)))
-    (lexical-let ((lex-ws websocket)
-                  (lex-frame frame))
-      (cond ((memq opcode '(continuation text binary))
-             (lambda () (websocket-try-callback 'websocket-on-message 
'on-message
-                                           lex-ws lex-frame)))
-            ((eq opcode 'ping)
-             (lambda () (websocket-send lex-ws
-                                   (make-websocket-frame :opcode 'pong 
:completep t))))
-            ((eq opcode 'close)
-             (lambda () (delete-process (websocket-conn lex-ws))))
-            (t (lambda ()))))))
-
-(defun websocket-outer-filter (websocket output)
-  "Filter the WEBSOCKET server's OUTPUT.
-This will parse headers and process frames repeatedly until there
-is no more output or the connection closes.  If the websocket
-connection is invalid, the connection will be closed."
-  (websocket-debug websocket "Received: %s" output)
-  (let ((start-point)
-        (end-point 0)
-        (text (concat (websocket-inflight-input websocket) output))
-        (header-end-pos))
-    ;; If we've received the complete header, check to see if we've
-    ;; received the desired handshake.
-    (when (and (eq 'connecting (websocket-ready-state websocket))
-               (setq header-end-pos (string-match "\r\n\r\n" text))
-               (setq start-point (+ 4 header-end-pos)))
-      (condition-case err
-          (progn
-            (websocket-verify-response-code text)
-            (websocket-verify-headers websocket text))
-        (error
-         (websocket-close websocket)
-         (signal (car err) (cdr err))))
-      (setf (websocket-ready-state websocket) 'open)
-      (websocket-try-callback 'websocket-on-open 'on-open websocket))
-    (when (eq 'open (websocket-ready-state websocket))
-      (websocket-process-input-on-open-ws
-       websocket (substring text (or start-point 0))))))
-
-(defun websocket-process-input-on-open-ws (websocket text)
-  "This handles input processing for both the client and server filters."
-  (let ((current-frame)
-        (processing-queue)
-        (start-point 0))
-    (while (setq current-frame (websocket-read-frame
-                                (substring text start-point)))
-      (push (websocket-process-frame websocket current-frame) processing-queue)
-      (incf start-point (websocket-frame-length current-frame)))
-    (when (> (length text) start-point)
-      (setf (websocket-inflight-input websocket)
-            (substring text start-point)))
-    (dolist (to-process (nreverse processing-queue))
-      (funcall to-process))))
-
-(defun websocket-send-text (websocket text)
-  "To the WEBSOCKET, send TEXT as a complete frame."
-  (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
-                                                  :completep t)))
-
-(defun websocket-check (frame)
-  "Check FRAME for correctness, returning true if correct."
-  (and (equal (not (memq (websocket-frame-opcode frame)
-                         '(continuation text binary)))
-              (and (not (websocket-frame-payload frame))
-                   (websocket-frame-completep frame)))))
-
-(defun websocket-send (websocket frame)
-  "To the WEBSOCKET server, send the FRAME.
-This will raise an error if the frame is illegal.
-
-The error signaled may be of type `websocket-illegal-frame' if
-the frame is malformed in some way, also having the condition
-type of `websocket-error'.  The data associated with the signal
-is the frame being sent.
-
-If the websocket is closed a signal `websocket-closed' is sent,
-also with `websocket-error' condition.  The data in the signal is
-also the frame.
-
-The frame may be too large for this buid of emacs, in which case
-`websocket-frame-too-large' is returned, with the data of the
-system's `most-positive-fixnum', whose length was exceeded.  This
-also has the `websocket-error' condition."
-  (unless (websocket-check frame)
-    (signal 'websocket-illegal-frame frame))
-  (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
-                   (websocket-frame-opcode frame)
-                   (websocket-frame-payload frame))
-  (websocket-ensure-connected websocket)
-  (unless (websocket-openp websocket)
-    (signal 'websocket-closed frame))
-  (process-send-string (websocket-conn websocket)
-                       (websocket-encode-frame frame)))
-
-(defun websocket-openp (websocket)
-  "Check WEBSOCKET and return non-nil if it is open, and either
-connecting or open."
-  (and websocket
-       (not (eq 'close (websocket-ready-state websocket)))
-       (member (process-status (websocket-conn websocket)) '(open run))))
-
-(defun websocket-close (websocket)
-  "Close WEBSOCKET and erase all the old websocket data."
-  (websocket-debug websocket "Closing websocket")
-  (when (websocket-openp websocket)
-    (websocket-send websocket
-                    (make-websocket-frame :opcode 'close
-                                          :completep t))
-    (setf (websocket-ready-state websocket) 'closed))
-  ;; Do we want to kill this?  It may result in on-closed not being
-  ;; called.
-  (kill-buffer (process-buffer (websocket-conn websocket))))
-
-(defun websocket-ensure-connected (websocket)
-  "If the WEBSOCKET connection is closed, open it."
-  (unless (and (websocket-conn websocket)
-               (ecase (process-status (websocket-conn websocket))
-                 ((run open listen) t)
-                 ((stop exit signal closed connect failed nil) nil)))
-    (websocket-close websocket)
-    (websocket-open (websocket-url websocket)
-                    :protocols (websocket-protocols websocket)
-                    :extensions (websocket-extensions websocket)
-                    :on-open (websocket-on-open websocket)
-                    :on-message (websocket-on-message websocket)
-                    :on-close (websocket-on-close websocket)
-                    :on-error (websocket-on-error websocket))))
+(defun websocket-verify-client-headers (output)
+  "Verify the headers from the WEBSOCKET client connection in OUTPUT.
+Unlike `websocket-verify-headers', this is a quieter routine.  We
+don't want to error due to a bad client, so we just print out
+messages and a plist containing `:key', the websocket key,
+`:protocols' and `:extensions'."
+  (block nil
+    (let ((case-fold-search t)
+          (plist))
+      (unless (string-match "HTTP/1.1" output)
+        (message "Websocket client connection: HTTP/1.1 not found")
+        (return nil))
+      (unless (string-match "^Host: " output)
+        (message "Websocket client connection: Host header not found")
+        (return nil))
+      (unless (string-match "^Upgrade: websocket\r\n" output)
+        (message "Websocket client connection: Upgrade: websocket not found")
+        (return nil))
+      (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output)
+          (setq plist (plist-put plist :key (match-string 1 output)))
+        (message "Websocket client connect: No key sent")
+        (return nil))
+      (unless (string-match "^Sec-WebSocket-Version: 13" output)
+        (message "Websocket client connect: Websocket version 13 not found")
+        (return nil))
+      (when (string-match "^Sec-WebSocket-Protocol:" output)
+        (setq plist (plist-put plist :protocols (websocket-parse-repeated-field
+                                                 output
+                                                 "Sec-Websocket-Protocol"))))
+      (when (string-match "^Sec-WebSocket-Extensions:" output)
+        (setq plist (plist-put plist :extensions 
(websocket-parse-repeated-field
+                                                  output
+                                                  
"Sec-Websocket-Extensions"))))
+      plist)))
 
 (provide 'websocket)
 

commit 489a4b8d3930eeb9afb129b4dcda544efcafa4b3
Author: Andrew Hyatt <address@hidden>
Date:   Mon Aug 13 00:33:14 2012 -0400

    Fix multibyte issues

diff --git a/websocket.el b/websocket.el
index f013756..1974761 100644
--- a/websocket.el
+++ b/websocket.el
@@ -528,7 +528,10 @@ describing the problem with the frame.
              :protocols (process-get server :protocol)
              :extensions (mapcar 'car (process-get server :extensions)))))
     (process-put client :websocket ws)
-    (set-process-filter client 'websocket-server-filter)))
+    (set-process-filter client 'websocket-server-filter)
+    ;; set-process-filter-multibyte is obsolete, but make-network-process's
+    ;; :filter-multibyte arg does not seem to do anything.
+    (set-process-filter-multibyte client nil)))
 
 (defun websocket-verify-client-headers (output)
   "Verify the headers from the WEBSOCKET client connection in OUTPUT.

commit 74d5c10c17eacbfd2f70ac5b8e9f73592040ded2
Author: Andrew Hyatt <address@hidden>
Date:   Sun Aug 12 22:56:49 2012 -0400

    Fix many issues with server connections.
    
    There is still an issue with multibyte strings, though.

diff --git a/websocket-test.el b/websocket-test.el
index ee8ff2a..9fc6e3b 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -202,7 +202,8 @@
         (base-headers (concat "Host: www.example.com\r\n"
                               "Upgrade: websocket\r\n"
                               "Connection: Upgrade\r\n"
-                              "Sec-WebSocket-Key: key\r\n"
+                              (format "Sec-WebSocket-Key: %s\r\n"
+                                      (websocket-calculate-accept "key"))
                               "Origin: mysystem\r\n"
                               "Sec-WebSocket-Version: 13\r\n")))
     (should (equal (concat base-headers "\r\n")
@@ -509,3 +510,33 @@
        (should-not closed)
        (should (equal response "response"))
        (should processed)))))
+
+(ert-deftest websocket-complete-server-response-test ()
+  ;; Example taken from RFC
+  (should (equal
+           (concat "HTTP/1.1 101 Switching Protocols\r\n"
+                   "Upgrade: websocket\r\n"
+                   "Connection: Upgrade\r\n"
+                   "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+                   "Sec-WebSocket-Protocol: chat\r\n\r\n"
+                   )
+           (let ((header-info
+                          (websocket-verify-client-headers
+                           (concat "GET /chat HTTP/1.1\r\n"
+                                   "Host: server.example.com\r\n"
+                                   "Upgrade: websocket\r\n"
+                                   "Connection: Upgrade\r\n"
+                                   "Sec-WebSocket-Key: 
dGhlIHNhbXBsZSBub25jZQ==\r\n"
+                                   "Origin: http://example.com\r\n";
+                                   "Sec-WebSocket-Protocol: chat, 
superchat\r\n"
+                                   "Sec-WebSocket-Version: 13\r\n"))))
+                     (should header-info)
+                     (let ((ws (websocket-inner-create
+                                :conn t :url t
+                                :accept-string (websocket-calculate-accept
+                                                (plist-get header-info :key))
+                                :protocols '("chat"))))
+                       (websocket-get-server-response
+                        ws
+                        (plist-get header-info :protocols)
+                        (plist-get header-info :extension)))))))
diff --git a/websocket.el b/websocket.el
index b013bca..f013756 100644
--- a/websocket.el
+++ b/websocket.el
@@ -521,11 +521,12 @@ describing the problem with the frame.
   (message "Connected from %S: %s" client message)
   (let ((ws (websocket-inner-create
              :conn client
-             :on-open (or (process-get proc :on-open) 'identity)
-             :on-message (or (process-get proc :on-message) (lambda (ws 
frame)))
-             :on-error (or (process-get proc :on-error) 'identity)
-             :protocol (process-get proc :protocol)
-             :extensions (mapcar 'car (process-get proc :extensions)))))
+             :url client
+             :on-open (or (process-get server :on-open) 'identity)
+             :on-message (or (process-get server :on-message) (lambda (ws 
frame)))
+             :on-error (or (process-get server :on-error) 'identity)
+             :protocols (process-get server :protocol)
+             :extensions (mapcar 'car (process-get server :extensions)))))
     (process-put client :websocket ws)
     (set-process-filter client 'websocket-server-filter)))
 
@@ -538,7 +539,7 @@ messages and a plist containing `:key', the websocket key,
   (block nil
     (let ((case-fold-search t)
           (plist))
-      (unless (string-match "^HTTP/1.1" output)
+      (unless (string-match "HTTP/1.1" output)
         (message "Websocket client connection: HTTP/1.1 not found")
         (return nil))
       (unless (string-match "^Host: " output)
@@ -548,18 +549,17 @@ messages and a plist containing `:key', the websocket key,
         (message "Websocket client connection: Upgrade: websocket not found")
         (return nil))
       (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output)
-          (setq plist (plist-put plist :key (base64-decode-string
-                                             (match-string 1 output))))
+          (setq plist (plist-put plist :key (match-string 1 output)))
         (message "Websocket client connect: No key sent")
         (return nil))
       (unless (string-match "^Sec-WebSocket-Version: 13" output)
         (message "Websocket client connect: Websocket version 13 not found")
         (return nil))
-      (when (string-match "^Sec-WebSocket-Protocol: \\([[:graph:]]+\\)\r\n" 
output)
+      (when (string-match "^Sec-WebSocket-Protocol:" output)
         (setq plist (plist-put plist :protocols (websocket-parse-repeated-field
                                                  output
                                                  "Sec-Websocket-Protocol"))))
-      (when (string-match "^Sec-WebSocket-Extensions: \\([[:graph:]]+\\)\r\n" 
output)
+      (when (string-match "^Sec-WebSocket-Extensions:" output)
         (setq plist (plist-put plist :extensions 
(websocket-parse-repeated-field
                                                   output
                                                   
"Sec-Websocket-Extensions"))))
@@ -577,7 +577,7 @@ messages and a plist containing `:key', the websocket key,
                     (when pos (+ 4 pos)))))
                (if end-of-header-pos
                    (progn
-                     (let ((header-info (websocket-verify-client-headers ws 
text)))
+                     (let ((header-info (websocket-verify-client-headers 
text)))
                        (if header-info
                            (progn (setf (websocket-accept-string ws)
                                         (websocket-calculate-accept
@@ -639,12 +639,14 @@ messages and a plist containing `:key', the websocket key,
               separator)))
 
 (defun* websocket-server (port &rest plist)
-  "Open a websocket server on PORT."
+  "Open a websocket server on PORT.
+PORT can be `t' to get a random port."
   (let* ((conn (make-network-process
                 :name (format "websocket server on port %d" port)
                 :server t
                 :family 'ipv4
                 :log 'websocket-server-accept
+                :filter-multibyte nil
                 :plist plist
                 :host 'local
                 :service port
@@ -832,7 +834,7 @@ connection is invalid, the connection will be closed."
       (setf (websocket-inflight-input websocket)
             (substring text start-point)))
     (dolist (to-process (nreverse processing-queue))
-      (funcall to-process)))))
+      (funcall to-process))))
 
 (defun websocket-send-text (websocket text)
   "To the WEBSOCKET, send TEXT as a complete frame."

commit 0202adc6b67cf74575d090be9c94f4111aaf6798
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 11 22:36:20 2012 -0400

    Finish and test the server filter function.

diff --git a/websocket-test.el b/websocket-test.el
index df839d6..ee8ff2a 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -1,4 +1,4 @@
-;;; websocket-test.el --- Unit tests for the websocket layer
+;; websocket-test.el --- Unit tests for the websocket layer
 
 ;; Copyright (c) 2010 Andrew Hyatt
 ;;
@@ -475,18 +475,37 @@
       (should (string-match "Sec-Websocket-Extensions: sea\r\n" output))
       (should (string-match "Sec-Websocket-Extensions: seb\r\n" output)))))
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+(ert-deftest websocket-server-filter ()
+  (let ((on-open-called)
+        (ws (websocket-inner-create :conn t :url t :accept-string "key"
+                                    :on-open (lambda (ws) (setq on-open-called 
t))))
+        (closed)
+        (response)
+        (processed))
+    (flet ((process-send-string (p text) (setq response text))
+           (websocket-close (ws) (setq closed t))
+           (process-get (process sym) ws))
+     ;; Bad request, in two parts
+     (flet ((websocket-verify-client-headers (ws text) nil))
+       (websocket-server-filter nil "HTTP/1.0 GET /foo \r\n")
+       (should-not closed)
+       (websocket-server-filter nil "\r\n")
+       (should (equal response "HTTP/1.1 400 Bad Request\r\n\r\n"))
+       (should-not (websocket-inflight-input ws)))
+    ;; Good request, followed by packet
+     (setq closed nil
+           response nil)
+     (setf (websocket-inflight-input ws) nil)
+     (flet ((websocket-verify-client-headers (ws text) t)
+            (websocket-get-server-response (ws protocols extensions)
+                                           "response")
+            (websocket-process-input-on-open-ws (ws text)
+                                                (setq processed t)
+                                                (should
+                                                 (equal text 
websocket-test-hello))))
+       (websocket-server-filter nil
+                                (concat "\r\n\r\n" websocket-test-hello))
+       (should (equal (websocket-ready-state ws) 'open))
+       (should-not closed)
+       (should (equal response "response"))
+       (should processed)))))
diff --git a/websocket.el b/websocket.el
index 8dc34d3..b013bca 100644
--- a/websocket.el
+++ b/websocket.el
@@ -566,26 +566,40 @@ messages and a plist containing `:key', the websocket key,
       plist)))
 
 (defun websocket-server-filter (process output)
-  (let ((ws (process-get process :websocket)))
+  "This acts on all OUTPUT from websocket clients PROCESS."
+  (let* ((ws (process-get process :websocket))
+         (text (concat (websocket-inflight-input ws) output)))
+    (setf (websocket-inflight-input ws) nil)
     (cond ((eq (websocket-ready-state ws) 'connecting)
            ;; check for connection string
-           (when (string-match "\r\n\r\n" output)
-             (let ((header-info (websocket-verify-client-headers ws output)))
-               (if header-info
-                   (progn (setf (websocket-ready-state ws) 'open)
-                          (websocket-server-filter process output)
-                          (setf (websocket-accept-string ws)
-                                (websocket-calculate-accept
-                                 (plist-get header-info :key)))
-                          (process-send-string
-                           (websocket-get-server-response
-                            ws (plist-get header-info :protocols)
-                            (plist-get header-info :extensions))))
-                   (message "Invalid client headers found in: %s" output)
-                 (websocket-close ws)))))
+           (let ((end-of-header-pos
+                  (let ((pos (string-match "\r\n\r\n" text)))
+                    (when pos (+ 4 pos)))))
+               (if end-of-header-pos
+                   (progn
+                     (let ((header-info (websocket-verify-client-headers ws 
text)))
+                       (if header-info
+                           (progn (setf (websocket-accept-string ws)
+                                        (websocket-calculate-accept
+                                         (plist-get header-info :key)))
+                                  (process-send-string
+                                   process
+                                   (websocket-get-server-response
+                                    ws (plist-get header-info :protocols)
+                                    (plist-get header-info :extensions)))
+                                  (setf (websocket-ready-state ws) 'open)
+                                  (websocket-try-callback 'websocket-on-open
+                                                          'on-open ws))
+                         (message "Invalid client headers found in: %s" output)
+                         (process-send-string process "HTTP/1.1 400 Bad 
Request\r\n\r\n")
+                         (websocket-close ws)))
+                     (when (> (length text) (+ 1 end-of-header-pos))
+                       (websocket-server-filter process (substring
+                                                           text
+                                                           
end-of-header-pos))))
+                 (setf (websocket-inflight-input ws) text))))
           ((eq (websocket-ready-state ws) 'open)
-           ;; process ouput
-           )
+           (websocket-process-input-on-open-ws ws text))
           ((eq (websocket-ready-state ws) 'closed)
            (message "WARNING: Should not have received further input on closed 
websocket")))))
 
@@ -786,8 +800,7 @@ connection is invalid, the connection will be closed."
   (let ((start-point)
         (end-point 0)
         (text (concat (websocket-inflight-input websocket) output))
-        (header-end-pos)
-        (processing-queue))
+        (header-end-pos))
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
     (when (and (eq 'connecting (websocket-ready-state websocket))
@@ -803,16 +816,23 @@ connection is invalid, the connection will be closed."
       (setf (websocket-ready-state websocket) 'open)
       (websocket-try-callback 'websocket-on-open 'on-open websocket))
     (when (eq 'open (websocket-ready-state websocket))
-      (unless start-point (setq start-point 0))
-      (let ((current-frame))
-        (while (and (setq current-frame (websocket-read-frame
-                                         (substring text start-point))))
-          (push (websocket-process-frame websocket current-frame) 
processing-queue)
-          (incf start-point (websocket-frame-length current-frame)))))
-    (setf (websocket-inflight-input websocket)
-        (substring text (or start-point 0)))
+      (websocket-process-input-on-open-ws
+       websocket (substring text (or start-point 0))))))
+
+(defun websocket-process-input-on-open-ws (websocket text)
+  "This handles input processing for both the client and server filters."
+  (let ((current-frame)
+        (processing-queue)
+        (start-point 0))
+    (while (setq current-frame (websocket-read-frame
+                                (substring text start-point)))
+      (push (websocket-process-frame websocket current-frame) processing-queue)
+      (incf start-point (websocket-frame-length current-frame)))
+    (when (> (length text) start-point)
+      (setf (websocket-inflight-input websocket)
+            (substring text start-point)))
     (dolist (to-process (nreverse processing-queue))
-      (funcall to-process))))
+      (funcall to-process)))))
 
 (defun websocket-send-text (websocket text)
   "To the WEBSOCKET, send TEXT as a complete frame."

commit 1f2f140ea03fcbc561200aa2808f6a120758eee6
Merge: 0777d93 b5bdb10
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 11 17:14:33 2012 -0400

    Merge in master branch

diff --cc websocket-test.el
index 5d9c7a4,7187aa0..df839d6
--- a/websocket-test.el
+++ b/websocket-test.el
@@@ -394,83 -406,9 +408,85 @@@
      (should-error (websocket-send ws
                                    (make-websocket-frame :opcode 'close
                                                          :payload "bye!"
-                                                         :completep t)))
+                                                         :completep t))
+                   :type 'websocket-illegal-frame)
      (should-error (websocket-send ws
-                                   (make-websocket-frame :opcode :close)))))
+                                   (make-websocket-frame :opcode :close))
+                   :type 'websocket-illegal-frame)))
  
 +(ert-deftest websocket-verify-client-headers ()
 +  (let* ((http "HTTP/1.1")
 +         (host "Host: authority")
 +         (upgrade "Upgrade: websocket")
 +         (key (format "Sec-Websocket-Key: %s" (base64-encode-string "key")))
 +         (version "Sec-Websocket-Version: 13")
 +         (origin "Origin: origin")
 +         (protocol "Sec-Websocket-Protocol: protocol")
 +         (extensions1 "Sec-Websocket-Extensions: foo")
 +         (extensions2 "Sec-Websocket-Extensions: bar; baz=2")
 +         (all-required-headers (list host upgrade key version)))
 +    ;; Test that all these headers are necessary
 +    (should (equal
 +             '(:key "key" :protocols ("protocol") :extensions ("foo" "bar; 
baz=2"))
 +             (websocket-verify-client-headers
 +              (mapconcat 'identity (append (list http "" protocol extensions1 
extensions2)
 +                                           all-required-headers) "\r\n"))))
 +    (should (websocket-verify-client-headers
 +              (mapconcat 'identity
 +                         (mapcar 'upcase
 +                                 (append (list http "" protocol extensions1 
extensions2)
 +                                         all-required-headers)) "\r\n")))
 +    (dolist (header all-required-headers)
 +      (should-not (websocket-verify-client-headers
 +                   (mapconcat 'identity (append (list http "")
 +                                                (remove header 
all-required-headers))
 +                              "\r\n"))))
 +    (should-not (websocket-verify-client-headers
 +                 (mapconcat 'identity (append (list "HTTP/1.0" "") 
all-required-headers)
 +                            "\r\n")))))
 +
 +(ert-deftest websocket-intersect ()
 +  (should (equal '(2) (websocket-intersect '(1 2) '(2 3))))
 +  (should (equal nil (websocket-intersect '(1 2) '(3 4))))
 +  (should (equal '(1 2) (websocket-intersect '(1 2) '(1 2)))))
 +
 +(ert-deftest websocket-get-server-response ()
 +  (let ((ws (websocket-inner-create :conn t :url t :accept-string "key"
 +                                    :protocols '("spa" "spb")
 +                                    :extensions '("sea" "seb"))))
 +    (should (equal (concat
 +                    "HTTP/1.1 101 Switching Protocols\r\n"
 +                    "Upgrade: websocket\r\n"
 +                    "Connection: Upgrade\r\n"
 +                    "Sec-WebSocket-Accept: key\r\n\r\n")
 +                   (websocket-get-server-response ws nil nil)))
 +    (should (string-match "Sec-Websocket-Protocol: spb\r\n"
 +                          (websocket-get-server-response ws '("spb" "spc") 
nil)))
 +    (should-not (string-match "Sec-Websocket-Protocol:"
 +                              (websocket-get-server-response ws '("spc") 
nil)))
 +    (let ((output (websocket-get-server-response ws '("spa" "spb") nil)))
 +      (should (string-match "Sec-Websocket-Protocol: spa\r\n" output))
 +      (should (string-match "Sec-Websocket-Protocol: spb\r\n" output)))
 +    (should (string-match "Sec-Websocket-Extensions: sea"
 +                          (websocket-get-server-response ws nil '("sea" 
"sec"))))
 +    (should-not (string-match "Sec-Websocket-Extensions:"
 +                              (websocket-get-server-response ws nil 
'("sec"))))
 +    (let ((output (websocket-get-server-response ws nil '("sea" "seb"))))
 +      (should (string-match "Sec-Websocket-Extensions: sea\r\n" output))
 +      (should (string-match "Sec-Websocket-Extensions: seb\r\n" output)))))
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
diff --cc websocket.el
index 3318c78,6c8cbab..8dc34d3
--- a/websocket.el
+++ b/websocket.el
@@@ -342,7 -350,36 +353,36 @@@ the frame finishes.  If the frame is no
    "The default error handler used to handle errors in callbacks."
    (message "Error found in callback `%S': %s" type (cdr err)))
  
+ ;; Error symbols in use by the library
+ (put 'websocket-unsupported-protocol 'error-conditions
+      '(error websocket-error websocket-unsupported-protocol))
+ (put 'websocket-unsupported-protocol 'error-message "Unsupport websocket 
protocol")
+ (put 'websocket-received-error-http-response 'error-conditions
+      '(error websocket-error websocket-received-error-http-response))
+ (put 'websocket-received-error-http-response 'error-message
+      "Error response received from websocket server")
+ (put 'websocket-invalid-header 'error-conditions
+      '(error websocket-error websocket-invalid-header))
+ (put 'websocket-invalid-header 'error-message
+      "Invalid HTTP header sent")
+ (put 'websocket-illegal-frame 'error-conditions
+      '(error websocket-error websocket-illegal-frame))
+ (put 'websocket-illegal-frame 'error-message
+      "Cannot send illegal frame to websocket")
+ (put 'websocket-closed 'error-conditions
+      '(error websocket-error websocket-closed))
+ (put 'websocket-closed 'error-message
+      "Cannot send message to a closed websocket")
+ (put 'websocket-unparseable-frame 'error-conditions
+      '(error websocket-error websocket-unparseable-frame))
+ (put 'websocket-unparseable-frame 'error-message
+      "Received an unparseable frame")
+ (put 'websocket-frame-too-large 'error-conditions
+      '(error websocket-error websocket-frame-too-large))
+ (put 'websocket-frame-too-large 'error-message
+      "The frame being sent is too large for this emacs to handle")
+ 
 -(defun* websocket-open (url &key protocol extensions (on-open 'identity)
 +(defun* websocket-open (url &key protocols extensions (on-open 'identity)
                              (on-message (lambda (w f))) (on-close 'identity)
                              (on-error 'websocket-default-error-handler))
    "Open a websocket connection to URL, returning the `websocket' struct.
@@@ -631,23 -551,10 +692,23 @@@ A t value will be returned on success, 
  if not."
    (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
    (unless (equal "101" (match-string 1 output))
-        (error "Bad HTTP response code while opening websocket connection: %s"
-               (match-string 1 output)))
+        (signal 'websocket-received-error-http-response
+                (string-to-int (match-string 1 output))))
    t)
  
 +(defun websocket-parse-repeated-field (output field)
 +  "From header-containing OUTPUT, parse out the list from a
 +possibly repeated field."
 +  (let ((pos 0)
 +        (extensions))
 +    (while (and pos
 +                (string-match (format "\r\n%s: \\(.*\\)\r\n" field)
 +                              output pos))
 +      (when (setq pos (match-end 1))
 +        (setq extensions (append extensions (split-string
 +                                             (match-string 1 output) ", 
?")))))
 +    extensions))
 +
  (defun websocket-verify-headers (websocket output)
    "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
  The output is assumed to have complete headers.  This function
@@@ -661,36 -569,39 +723,38 @@@ of populating the list of server extens
    (let ((case-fold-search t))
      (websocket-debug websocket "Checking for upgrade header")
      (unless (string-match "\r\nUpgrade: websocket\r\n" output)
-       (error "No 'Upgrade: websocket' header found."))
+       (signal 'websocket-invalid-header
+               "No 'Upgrade: websocket' header found"))
      (websocket-debug websocket "Checking for connection header")
      (unless (string-match "\r\nConnection: upgrade\r\n" output)
-       (error "No 'Connection: upgrade' header found"))
+       (signal 'websocket-invalid-header
+               "No 'Connection: upgrade' header found"))
 -    (when (websocket-protocol websocket)
 -      (websocket-debug websocket "Checking for protocol match: %s"
 -                       (websocket-protocol websocket))
 -      (unless (string-match
 +    (when (websocket-protocols websocket)
 +      (dolist (protocol (websocket-protocols websocket))
 +        (websocket-debug websocket "Checking for protocol match: %s"
 +                         protocol)
 +        (let ((protocols))
 +          (if (string-match
                 (format "\r\nSec-Websocket-Protocol: %s\r\n"
 -                       (websocket-protocol websocket)) output)
 +                       protocol) output)
 +              (add-to-list 'protocols protocol)
-             (error "Incorrect or missing protocol (%s) returned by the 
server."
-                    protocol))
++            (signal 'websocket-invalid-header
++                    "Incorrect or missing protocol returned by the server."))
 +          (setf (websocket-negotiated-protocols websocket) protocols))))
 +    (let* ((extensions (websocket-parse-repeated-field
 +                        output
 +                        "Sec-WebSocket-Extensions"))
 +           (extra-extensions))
 +      (dolist (ext extensions)
 +        (when (not (member
 +                    (first (split-string ext "; ?"))
 +                    (websocket-extensions websocket)))
 +          (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
 +      (when extra-extensions
-         (error "Non-requested extensions returned by server: %s"
-                extra-extensions))
+         (signal 'websocket-invalid-header
 -                "Incorrect or missing protocol returned by the server.")))
 -    (let ((pos 0)
 -          (extensions))
 -      (while (and pos
 -                  (string-match "\r\nSec-Websocket-Extensions: \\(.*\\)\r\n"
 -                      output pos))
 -        (when (setq pos (match-end 1))
 -          (setq extensions (append extensions (split-string
 -                                               (match-string 1 output) ", 
?")))))
 -      (let ((extra-extensions))
 -        (dolist (ext extensions)
 -          (when (not (member
 -                      (first (split-string ext "; ?"))
 -                      (websocket-extensions websocket)))
 -            (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
 -        (when extra-extensions
 -          (signal 'websocket-invalid-header
 -                  (format "Non-requested extensions returned by server: %S" 
extra-extensions))))
 -      (setf (websocket-server-extensions websocket) extensions)))
 -  ;; return true
++                (format "Non-requested extensions returned by server: %S"
++                        extra-extensions)))
 +      (setf (websocket-negotiated-extensions websocket) extensions)))
-   ;; return true
    t)
  
  (defun websocket-process-frame (websocket frame)

commit 0777d9397fb52f2c98b197339865179d326d47ef
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 11 17:07:08 2012 -0400

    Minor indentation fix

diff --git a/websocket.el b/websocket.el
index 8c36ecf..3318c78 100644
--- a/websocket.el
+++ b/websocket.el
@@ -519,9 +519,10 @@ messages and a plist containing `:key', the websocket key,
                           (setf (websocket-accept-string ws)
                                 (websocket-calculate-accept
                                  (plist-get header-info :key)))
-                          (process-send-string (websocket-get-server-response
-                                                ws (plist-get header-info 
:protocols)
-                                                (plist-get header-info 
:extensions))))
+                          (process-send-string
+                           (websocket-get-server-response
+                            ws (plist-get header-info :protocols)
+                            (plist-get header-info :extensions))))
                    (message "Invalid client headers found in: %s" output)
                  (websocket-close ws)))))
           ((eq (websocket-ready-state ws) 'open)

commit 5a8b995a509acaaacdc33b72149b556d97bfc53a
Author: Andrew Hyatt <address@hidden>
Date:   Sat Aug 11 00:05:01 2012 -0400

    Add server header generation, and refactor protocol and extension handling.

diff --git a/websocket-test.el b/websocket-test.el
index 63a09ce..5d9c7a4 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -130,7 +130,7 @@
          (websocket-inner-create
              :conn "fake-conn" :url "ws://foo/bar"
              :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
-             :protocol "myprotocol"))
+             :protocols '("myprotocol")))
         (ws-with-extensions
          (websocket-inner-create
              :conn "fake-conn" :url "ws://foo/bar"
@@ -165,6 +165,8 @@
       ws-with-protocol
       (websocket-test-header-with-lines accept upgrade connection
                                         "Sec-Websocket-Protocol: myprotocol")))
+    (should (equal '("myprotocol")
+                   (websocket-negotiated-protocols ws-with-protocol)))
     (should-error
      (websocket-verify-headers
       ws-with-extensions
@@ -176,7 +178,7 @@
       (websocket-test-header-with-lines
        accept upgrade connection "Sec-Websocket-Extensions: ext1, ext2; a=1")))
     (should (equal '("ext1" "ext2; a=1")
-                   (websocket-server-extensions ws-with-extensions)))
+                   (websocket-negotiated-extensions ws-with-extensions)))
     (should
      (websocket-verify-headers
       ws-with-extensions
@@ -184,7 +186,7 @@
                                         "Sec-Websocket-Extensions: ext1"
                                         "Sec-Websocket-Extensions: ext2; 
a=1")))
     (should (equal '("ext1" "ext2; a=1")
-                   (websocket-server-extensions ws-with-extensions)))))
+                   (websocket-negotiated-extensions ws-with-extensions)))))
 
 (ert-deftest websocket-create-headers ()
   (let ((system-name "mysystem")
@@ -200,7 +202,7 @@
     (should (equal (concat base-headers
                            "Sec-WebSocket-Protocol: protocol\r\n\r\n")
                    (websocket-create-headers "ws://www.example.com/path"
-                                             "key" "protocol" nil)))
+                                             "key" '("protocol") nil)))
     (should (equal
              (concat base-headers
                      "Sec-WebSocket-Extensions: ext1; a; b=2, ext2\r\n\r\n")
@@ -400,7 +402,7 @@
   (let* ((http "HTTP/1.1")
          (host "Host: authority")
          (upgrade "Upgrade: websocket")
-         (key "Sec-Websocket-Key: key")
+         (key (format "Sec-Websocket-Key: %s" (base64-encode-string "key")))
          (version "Sec-Websocket-Version: 13")
          (origin "Origin: origin")
          (protocol "Sec-Websocket-Protocol: protocol")
@@ -427,3 +429,48 @@
                  (mapconcat 'identity (append (list "HTTP/1.0" "") 
all-required-headers)
                             "\r\n")))))
 
+(ert-deftest websocket-intersect ()
+  (should (equal '(2) (websocket-intersect '(1 2) '(2 3))))
+  (should (equal nil (websocket-intersect '(1 2) '(3 4))))
+  (should (equal '(1 2) (websocket-intersect '(1 2) '(1 2)))))
+
+(ert-deftest websocket-get-server-response ()
+  (let ((ws (websocket-inner-create :conn t :url t :accept-string "key"
+                                    :protocols '("spa" "spb")
+                                    :extensions '("sea" "seb"))))
+    (should (equal (concat
+                    "HTTP/1.1 101 Switching Protocols\r\n"
+                    "Upgrade: websocket\r\n"
+                    "Connection: Upgrade\r\n"
+                    "Sec-WebSocket-Accept: key\r\n\r\n")
+                   (websocket-get-server-response ws nil nil)))
+    (should (string-match "Sec-Websocket-Protocol: spb\r\n"
+                          (websocket-get-server-response ws '("spb" "spc") 
nil)))
+    (should-not (string-match "Sec-Websocket-Protocol:"
+                              (websocket-get-server-response ws '("spc") nil)))
+    (let ((output (websocket-get-server-response ws '("spa" "spb") nil)))
+      (should (string-match "Sec-Websocket-Protocol: spa\r\n" output))
+      (should (string-match "Sec-Websocket-Protocol: spb\r\n" output)))
+    (should (string-match "Sec-Websocket-Extensions: sea"
+                          (websocket-get-server-response ws nil '("sea" 
"sec"))))
+    (should-not (string-match "Sec-Websocket-Extensions:"
+                              (websocket-get-server-response ws nil '("sec"))))
+    (let ((output (websocket-get-server-response ws nil '("sea" "seb"))))
+      (should (string-match "Sec-Websocket-Extensions: sea\r\n" output))
+      (should (string-match "Sec-Websocket-Extensions: seb\r\n" output)))))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/websocket.el b/websocket.el
index 840e7b8..8c36ecf 100644
--- a/websocket.el
+++ b/websocket.el
@@ -66,8 +66,9 @@ called.
 `on-open', `on-message', `on-close', and `on-error' are described
 in `websocket-open'.
 
-The `server-extensions' slot lists the extensions accepted by the
-server.
+The `negotiated-extensions' slot lists the extensions accepted by
+both the client and server, and `negotiated-protocols' does the
+same for the protocols.
 "
   ;; API
   (ready-state 'connecting)
@@ -76,12 +77,13 @@ server.
   on-message
   on-close
   on-error
-  server-extensions
+  negotiated-protocols
+  negotiated-extensions
   (server-p nil :read-only t)
 
   ;; Other data - clients should not have to access this.
   (url (assert nil) :read-only t)
-  (protocol nil :read-only t)
+  (protocols nil :read-only t)
   (extensions nil :read-only t)
   (conn (assert nil) :read-only t)
   accept-string
@@ -340,13 +342,14 @@ the frame finishes.  If the frame is not completed, 
return NIL."
   "The default error handler used to handle errors in callbacks."
   (message "Error found in callback `%S': %s" type (cdr err)))
 
-(defun* websocket-open (url &key protocol extensions (on-open 'identity)
+(defun* websocket-open (url &key protocols extensions (on-open 'identity)
                             (on-message (lambda (w f))) (on-close 'identity)
                             (on-error 'websocket-default-error-handler))
   "Open a websocket connection to URL, returning the `websocket' struct.
 The PROTOCOL argument is optional, and setting it will declare to
-the server that this client supports the protocol.  We will
-require that the server also has to support that protocol.
+the server that this client supports the protocols in the list
+given.  We will require that the server also has to support that
+protocols.
 
 Similar logic applies to EXTENSIONS, which is a list of conses,
 the car of which is a string naming the extension, and the cdr of
@@ -413,7 +416,7 @@ websocket."
                      :on-message on-message
                      :on-close on-close
                      :on-error on-error
-                     :protocol protocol
+                     :protocols protocols
                      :extensions (mapcar 'car extensions)
                      :accept-string
                      (websocket-calculate-accept key))))
@@ -487,7 +490,8 @@ messages and a plist containing `:key', the websocket key,
         (message "Websocket client connection: Upgrade: websocket not found")
         (return nil))
       (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output)
-          (setq plist (plist-put plist :key (match-string 1 output)))
+          (setq plist (plist-put plist :key (base64-decode-string
+                                             (match-string 1 output))))
         (message "Websocket client connect: No key sent")
         (return nil))
       (unless (string-match "^Sec-WebSocket-Version: 13" output)
@@ -508,17 +512,59 @@ messages and a plist containing `:key', the websocket key,
     (cond ((eq (websocket-ready-state ws) 'connecting)
            ;; check for connection string
            (when (string-match "\r\n\r\n" output)
-             (if (websocket-verify-client-headers ws output)
-                 (progn (setf (websocket-ready-state ws) 'open)
-                        (websocket-server-filter process output))
-               (message "Invalid client headers found in: %s" output)
-               (websocket-close ws))))
+             (let ((header-info (websocket-verify-client-headers ws output)))
+               (if header-info
+                   (progn (setf (websocket-ready-state ws) 'open)
+                          (websocket-server-filter process output)
+                          (setf (websocket-accept-string ws)
+                                (websocket-calculate-accept
+                                 (plist-get header-info :key)))
+                          (process-send-string (websocket-get-server-response
+                                                ws (plist-get header-info 
:protocols)
+                                                (plist-get header-info 
:extensions))))
+                   (message "Invalid client headers found in: %s" output)
+                 (websocket-close ws)))))
           ((eq (websocket-ready-state ws) 'open)
            ;; process ouput
            )
           ((eq (websocket-ready-state ws) 'closed)
            (message "WARNING: Should not have received further input on closed 
websocket")))))
 
+(defun websocket-intersect (a b)
+  "Simple list intersection, should function like common lisp's 
`intersection'."
+  (let ((result))
+    (dolist (elem a (nreverse result))
+      (when (member elem b)
+        (add-to-list 'result elem)))))
+
+(defun websocket-get-server-response (websocket client-protocols 
client-extensions)
+  "Get the websocket response from client WEBSOCKET."
+  (let ((separator "\r\n"))
+      (concat "HTTP/1.1 101 Switching Protocols" separator
+              "Upgrade: websocket" separator
+              "Connection: Upgrade" separator
+              "Sec-WebSocket-Accept: "
+              (websocket-accept-string websocket) separator
+              (let ((protocols
+                         (websocket-intersect client-protocols
+                                              (websocket-protocols 
websocket))))
+                    (when protocols
+                      (concat
+                       (mapconcat
+                        (lambda (protocol) (format "Sec-WebSocket-Protocol: %s"
+                                              protocol)) protocols separator)
+                       separator)))
+              (let ((extensions (websocket-intersect
+                                   client-extensions
+                                   (websocket-extensions websocket))))
+                  (when extensions
+                    (concat
+                     (mapconcat
+                      (lambda (extension) (format "Sec-Websocket-Extensions: 
%s"
+                                             extension)) extensions separator)
+                     separator)))
+              separator)))
+
 (defun* websocket-server (port &rest plist)
   "Open a websocket server on PORT."
   (let* ((conn (make-network-process
@@ -541,7 +587,11 @@ These are defined as in `websocket-open'."
                   "Origin: %s\r\n"
                   "Sec-WebSocket-Version: 13\r\n"
                   (when protocol
-                    "Sec-WebSocket-Protocol: %s\r\n")
+                    (concat
+                     (mapconcat (lambda (protocol)
+                                  (format "Sec-WebSocket-Protocol: %s" 
protocol))
+                                protocol "\r\n")
+                     "\r\n"))
                   (when extensions
                     (format "Sec-WebSocket-Extensions: %s\r\n"
                             (mapconcat
@@ -614,14 +664,18 @@ of populating the list of server extensions to WEBSOCKET."
     (websocket-debug websocket "Checking for connection header")
     (unless (string-match "\r\nConnection: upgrade\r\n" output)
       (error "No 'Connection: upgrade' header found"))
-    ;; TODO(ahyatt) Implement checking for extensions
-    (when (websocket-protocol websocket)
-      (websocket-debug websocket "Checking for protocol match: %s"
-                       (websocket-protocol websocket))
-      (unless (string-match
+    (when (websocket-protocols websocket)
+      (dolist (protocol (websocket-protocols websocket))
+        (websocket-debug websocket "Checking for protocol match: %s"
+                         protocol)
+        (let ((protocols))
+          (if (string-match
                (format "\r\nSec-Websocket-Protocol: %s\r\n"
-                       (websocket-protocol websocket)) output)
-        (error "Incorrect or missing protocol returned by the server.")))
+                       protocol) output)
+              (add-to-list 'protocols protocol)
+            (error "Incorrect or missing protocol (%s) returned by the server."
+                   protocol))
+          (setf (websocket-negotiated-protocols websocket) protocols))))
     (let* ((extensions (websocket-parse-repeated-field
                         output
                         "Sec-WebSocket-Extensions"))
@@ -634,7 +688,7 @@ of populating the list of server extensions to WEBSOCKET."
       (when extra-extensions
         (error "Non-requested extensions returned by server: %s"
                extra-extensions))
-      (setf (websocket-server-extensions websocket) extensions)))
+      (setf (websocket-negotiated-extensions websocket) extensions)))
   ;; return true
   t)
 
@@ -748,7 +802,7 @@ connecting or open."
                  ((stop exit signal closed connect failed nil) nil)))
     (websocket-close websocket)
     (websocket-open (websocket-url websocket)
-                    :protocol (websocket-protocol websocket)
+                    :protocols (websocket-protocols websocket)
                     :extensions (websocket-extensions websocket)
                     :on-open (websocket-on-open websocket)
                     :on-message (websocket-on-message websocket)

commit b5bdb101548ea334b0969a5d35f9fbd39d438d21
Author: Andrew Hyatt <address@hidden>
Date:   Mon Aug 6 21:27:14 2012 -0400

    Disable undo in new debug buffer

diff --git a/websocket.el b/websocket.el
index 9248134..6c8cbab 100644
--- a/websocket.el
+++ b/websocket.el
@@ -527,8 +527,11 @@ These are defined as in `websocket-open'."
 
 (defun websocket-get-debug-buffer-create (websocket)
   "Get or create the buffer corresponding to WEBSOCKET."
-  (get-buffer-create (format "*websocket %s debug*"
-                             (websocket-url websocket))))
+  (let ((buf (get-buffer-create (format "*websocket %s debug*"
+                                    (websocket-url websocket)))))
+    (when (= 0 (buffer-size buf))
+      (buffer-disable-undo buf))
+    buf))
 
 (defun websocket-debug (websocket msg &rest args)
   "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."

commit e5531044a9c33ea129ce222be7c0cbe186a8db6d
Author: Andrew Hyatt <address@hidden>
Date:   Mon Aug 6 21:21:42 2012 -0400

    Remove space in front of websocket debug buffer.
    
    It should be viewable by users, after all, which the space gets in the way 
of.

diff --git a/websocket.el b/websocket.el
index 58dbfd4..9248134 100644
--- a/websocket.el
+++ b/websocket.el
@@ -527,7 +527,7 @@ These are defined as in `websocket-open'."
 
 (defun websocket-get-debug-buffer-create (websocket)
   "Get or create the buffer corresponding to WEBSOCKET."
-  (get-buffer-create (format " *websocket %s debug*"
+  (get-buffer-create (format "*websocket %s debug*"
                              (websocket-url websocket))))
 
 (defun websocket-debug (websocket msg &rest args)

commit 8904556565ffebd707e140fc95b53899ac026a38
Author: Andrew Hyatt <address@hidden>
Date:   Sun Aug 5 22:51:45 2012 -0400

    Switch from using generic errors, to using named symbols.

diff --git a/websocket-test.el b/websocket-test.el
index c20dab0..7187aa0 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -54,9 +54,9 @@
   (let ((f (lambda () (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8))))
     (if websocket-test-64-bit-p
         (should (equal #x100000001 (funcall f)))
-      (should-error (funcall f))))
+      (should-error (funcall f) :type 'websocket-unparseable-frame)))
   (should-error (websocket-get-bytes "\x0\x0\x0" 3))
-  (should-error (websocket-get-bytes "\x0" 2)))
+  (should-error (websocket-get-bytes "\x0" 2) :type 
'websocket-unparseable-frame))
 
 (ert-deftest websocket-get-opcode ()
   (should (equal 'text (websocket-get-opcode websocket-test-hello))))
@@ -115,8 +115,11 @@
 
 (ert-deftest websocket-verify-response-code ()
   (should (websocket-verify-response-code "HTTP/1.1 101"))
-  (should-error (websocket-verify-response-code "HTTP/1.1 400"))
-  (should-error (websocket-verify-response-code "HTTP/1.1 200")))
+  (should
+   (eq 400 (cdr (should-error (websocket-verify-response-code "HTTP/1.1 400")
+                          :type 'websocket-received-error-http-response))))
+  (should
+   (eq 200 (cdr (should-error (websocket-verify-response-code "HTTP/1.1 
200"))))))
 
 (ert-deftest websocket-verify-headers ()
   (let ((accept "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
@@ -142,24 +145,30 @@
     (should-error
      (websocket-verify-headers
       ws
-      (websocket-test-header-with-lines invalid-accept upgrade connection)))
+      (websocket-test-header-with-lines invalid-accept upgrade connection))
+     :type 'websocket-invalid-header)
     (should-error (websocket-verify-headers
                    ws
-                   (websocket-test-header-with-lines upgrade connection)))
+                   (websocket-test-header-with-lines upgrade connection))
+                  :type 'websocket-invalid-header)
     (should-error (websocket-verify-headers
                    ws
-                   (websocket-test-header-with-lines accept connection)))
+                   (websocket-test-header-with-lines accept connection))
+                  :type 'websocket-invalid-header)
     (should-error (websocket-verify-headers
                    ws
-                   (websocket-test-header-with-lines accept upgrade)))
+                   (websocket-test-header-with-lines accept upgrade))
+                  :type 'websocket-invalid-header)
     (should-error (websocket-verify-headers
                    ws-with-protocol
-                   (websocket-test-header-with-lines accept upgrade 
connection)))
+                   (websocket-test-header-with-lines accept upgrade 
connection))
+                  :type 'websocket-invalid-header)
     (should-error
      (websocket-verify-headers
       ws-with-protocol
       (websocket-test-header-with-lines accept upgrade connection
-                                        "Sec-Websocket-Protocol: foo")))
+                                        "Sec-Websocket-Protocol: foo"))
+     :type 'websocket-invalid-header)
     (should
      (websocket-verify-headers
       ws-with-protocol
@@ -363,9 +372,9 @@
       (should (equal (list frame2 frame1) processed-frames)))
     (flet ((websocket-ready-state (websocket) 'connecting)
            (websocket-close (websocket)))
-      (should (equal "Bad HTTP response code while opening websocket 
connection: 500"
-                     (car (cdr (should-error
-                                (websocket-outer-filter fake-ws "HTTP/1.1 
500\r\n\r\n")))))))))
+      (should (eq 500 (cdr (should-error
+                                (websocket-outer-filter fake-ws "HTTP/1.1 
500\r\n\r\n")
+                                :type 
'websocket-received-error-http-response)))))))
 
 (ert-deftest websocket-outer-filter-bad-connection ()
   (let* ((on-open-calledp)
@@ -393,11 +402,13 @@
       (websocket-send ws (make-websocket-frame :opcode 'ping
                                                        :completep t)))
     (should-error (websocket-send ws
-                                  (make-websocket-frame :opcode 'text )))
+                                  (make-websocket-frame :opcode 'text)))
     (should-error (websocket-send ws
                                   (make-websocket-frame :opcode 'close
                                                         :payload "bye!"
-                                                        :completep t)))
+                                                        :completep t))
+                  :type 'websocket-illegal-frame)
     (should-error (websocket-send ws
-                                  (make-websocket-frame :opcode :close)))))
+                                  (make-websocket-frame :opcode :close))
+                  :type 'websocket-illegal-frame)))
 
diff --git a/websocket.el b/websocket.el
index e9f8f8e..58dbfd4 100644
--- a/websocket.el
+++ b/websocket.el
@@ -188,17 +188,25 @@ power of 2, up to 8."
            (cval (calc-eval '("(2^32 * $ + $$)") nil
                             (aref 32-bit-parts 0) (aref 32-bit-parts 1))))
       (when (calc-eval '("$ > $$") 'pred cval most-positive-fixnum)
-        (error "websocket-get-bytes: value too large to parse!"))
+        (signal 'websocket-unparseable-frame
+                "Frame value found too large to parse!"))
       (string-to-number cval))
     ;; n is not 8
-    (bindat-get-field (bindat-unpack
-                     `((:val
-                        ,(cond ((= n 1) 'u8)
-                               ((= n 2) 'u16)
-                               ((= n 4) 'u32)
-                               (t (error
-                                   "websocket-get-bytes: Unknown N: %s" n)))))
-                     s) :val)))
+    (bindat-get-field
+     (condition-case err
+         (bindat-unpack
+          `((:val
+             ,(cond ((= n 1) 'u8)
+                    ((= n 2) 'u16)
+                    ((= n 4) 'u32)
+                    ;; This is an error with the library,
+                    ;; not a user-facing, meaningful error.
+                    (t (error
+                        "websocket-get-bytes: Unknown N: %s" n)))))
+          s)
+       (args-out-of-range (signal 'websocket-unparseable-frame
+                                  (format "Frame unexpectedly shortly: %s" 
s))))
+     :val)))
 
 (defun websocket-to-bytes (val nbytes)
   "Encode the integer VAL in NBYTES of data.
@@ -207,13 +215,15 @@ NBYTES much be a power of 2, up to 8."
                    (< val (expt 2 (* 8 nbytes))))
               (and (= nbytes 8)
                    (calc-eval "% < 2^(8 * %%)" 'pred val nbytes)))
-      (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
-             val nbytes))
+    ;; not a user-facing error, this must be caused from an error in
+    ;; this library
+    (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
+           val nbytes))
   (if (= nbytes 8)
       (progn
         (when (calc-eval "$ < 4294967296" 'pred most-positive-fixnum)
-          (error "Could not send an 8-byte value on this version of emacs.
-A 64-bit version of emacs may solve your problem."))
+          (signal 'websocket-frame-too-large
+                  most-positive-fixnum))
         ;; Need to use calc even though at this point things are manageable,
         ;; since some emacs cannot parse the value 4294967296, even if
         ;; they never evaluate it.
@@ -224,6 +234,7 @@ A 64-bit version of emacs may solve your problem."))
      `((:val ,(cond ((= nbytes 1) 'u8)
                     ((= nbytes 2) 'u16)
                     ((= nbytes 4) 'u32)
+                    ;; Library error, not system error
                     (t (error "websocket-to-bytes: Unknown NBYTES: %s" 
nbytes)))))
      `((:val . ,val)))))
 
@@ -339,6 +350,35 @@ the frame finishes.  If the frame is not completed, return 
NIL."
   "The default error handler used to handle errors in callbacks."
   (message "Error found in callback `%S': %s" type (cdr err)))
 
+;; Error symbols in use by the library
+(put 'websocket-unsupported-protocol 'error-conditions
+     '(error websocket-error websocket-unsupported-protocol))
+(put 'websocket-unsupported-protocol 'error-message "Unsupport websocket 
protocol")
+(put 'websocket-received-error-http-response 'error-conditions
+     '(error websocket-error websocket-received-error-http-response))
+(put 'websocket-received-error-http-response 'error-message
+     "Error response received from websocket server")
+(put 'websocket-invalid-header 'error-conditions
+     '(error websocket-error websocket-invalid-header))
+(put 'websocket-invalid-header 'error-message
+     "Invalid HTTP header sent")
+(put 'websocket-illegal-frame 'error-conditions
+     '(error websocket-error websocket-illegal-frame))
+(put 'websocket-illegal-frame 'error-message
+     "Cannot send illegal frame to websocket")
+(put 'websocket-closed 'error-conditions
+     '(error websocket-error websocket-closed))
+(put 'websocket-closed 'error-message
+     "Cannot send message to a closed websocket")
+(put 'websocket-unparseable-frame 'error-conditions
+     '(error websocket-error websocket-unparseable-frame))
+(put 'websocket-unparseable-frame 'error-message
+     "Received an unparseable frame")
+(put 'websocket-frame-too-large 'error-conditions
+     '(error websocket-error websocket-frame-too-large))
+(put 'websocket-frame-too-large 'error-message
+     "The frame being sent is too large for this emacs to handle")
+
 (defun* websocket-open (url &key protocol extensions (on-open 'identity)
                             (on-message (lambda (w f))) (on-close 'identity)
                             (on-error 'websocket-default-error-handler))
@@ -383,7 +423,24 @@ dangerous is the debugger is quit out of.  If not 
specified,
 
 For each of these event handlers, the client code can store
 arbitrary data in the `client-data' slot in the returned
-websocket."
+websocket.
+
+The following errors might be thrown in this method or in
+websocket processing, all of them having the error-condition
+`websocket-error' in addition to their own symbol:
+
+`websocket-unsupported-protocol': Data in the error signal is the
+protocol (such as \"wss\") that is unsupported.
+
+`websocket-received-error-http-response': Data in the error
+signal is the integer error number.
+
+`websocket-invalid-header': Data in the error is a string
+describing the invalid header received from the server.
+
+`websocket-unparseable-frame': Data in the error is a string
+describing the problem with the frame.
+"
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key (websocket-genkey))
@@ -403,8 +460,9 @@ websocket."
                                                  :service port :nowait nil)
                          (condition-case-no-debug nil
                              (open-network-stream name buf host port :type 
type :nowait nil)
-                           (wrong-number-of-arguments (error "No wss support 
in this Emacs version.")))))
-                 (error "Unknown protocol")))
+                           (wrong-number-of-arguments
+                            (signal 'websocket-unsupported-protocol "wss")))))
+                 (signal 'websocket-unsupported-protocol (url-type 
url-struct))))
          (websocket (websocket-inner-create
                      :conn conn
                      :url url
@@ -490,8 +548,8 @@ A t value will be returned on success, and an error thrown
 if not."
   (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
   (unless (equal "101" (match-string 1 output))
-       (error "Bad HTTP response code while opening websocket connection: %s"
-              (match-string 1 output)))
+       (signal 'websocket-received-error-http-response
+               (string-to-int (match-string 1 output))))
   t)
 
 (defun websocket-verify-headers (websocket output)
@@ -503,22 +561,25 @@ of populating the list of server extensions to WEBSOCKET."
          (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
     (websocket-debug websocket "Checking for accept header: %s" accept-string)
     (unless (string-match (regexp-quote accept-string) output)
-      (error "Incorrect handshake from websocket: is this really a websocket 
connection?")))
+      (signal 'websocket-invalid-header
+              "Incorrect handshake from websocket: is this really a websocket 
connection?")))
   (let ((case-fold-search t))
     (websocket-debug websocket "Checking for upgrade header")
     (unless (string-match "\r\nUpgrade: websocket\r\n" output)
-      (error "No 'Upgrade: websocket' header found."))
+      (signal 'websocket-invalid-header
+              "No 'Upgrade: websocket' header found"))
     (websocket-debug websocket "Checking for connection header")
     (unless (string-match "\r\nConnection: upgrade\r\n" output)
-      (error "No 'Connection: upgrade' header found"))
-    ;; TODO(ahyatt) Implement checking for extensions
+      (signal 'websocket-invalid-header
+              "No 'Connection: upgrade' header found"))
     (when (websocket-protocol websocket)
       (websocket-debug websocket "Checking for protocol match: %s"
                        (websocket-protocol websocket))
       (unless (string-match
                (format "\r\nSec-Websocket-Protocol: %s\r\n"
                        (websocket-protocol websocket)) output)
-        (error "Incorrect or missing protocol returned by the server.")))
+        (signal 'websocket-invalid-header
+                "Incorrect or missing protocol returned by the server.")))
     (let ((pos 0)
           (extensions))
       (while (and pos
@@ -534,8 +595,8 @@ of populating the list of server extensions to WEBSOCKET."
                       (websocket-extensions websocket)))
             (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
         (when extra-extensions
-          (error "Non-requested extensions returned by server: %s"
-                 extra-extensions)))
+          (signal 'websocket-invalid-header
+                  (format "Non-requested extensions returned by server: %S" 
extra-extensions))))
       (setf (websocket-server-extensions websocket) extensions)))
   ;; return true
   t)
@@ -611,15 +672,29 @@ connection is invalid, the connection will be closed."
 
 (defun websocket-send (websocket frame)
   "To the WEBSOCKET server, send the FRAME.
-This will raise an error if the frame is illegal."
+This will raise an error if the frame is illegal.
+
+The error signaled may be of type `websocket-illegal-frame' if
+the frame is malformed in some way, also having the condition
+type of `websocket-error'.  The data associated with the signal
+is the frame being sent.
+
+If the websocket is closed a signal `websocket-closed' is sent,
+also with `websocket-error' condition.  The data in the signal is
+also the frame.
+
+The frame may be too large for this buid of emacs, in which case
+`websocket-frame-too-large' is returned, with the data of the
+system's `most-positive-fixnum', whose length was exceeded.  This
+also has the `websocket-error' condition."
   (unless (websocket-check frame)
-    (error "Cannot send illegal frame to websocket"))
+    (signal 'websocket-illegal-frame frame))
   (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
                    (websocket-frame-opcode frame)
                    (websocket-frame-payload frame))
   (websocket-ensure-connected websocket)
   (unless (websocket-openp websocket)
-    (error "No webserver process to send data to!"))
+    (signal 'websocket-closed frame))
   (process-send-string (websocket-conn websocket)
                        (websocket-encode-frame frame)))
 

commit f5ab391dc686a27a3d6f070657d7279001c5d5d4
Merge: aeda944 4040ae0
Author: Andrew Hyatt <address@hidden>
Date:   Sun Aug 5 14:36:07 2012 -0700

    Merge pull request #23 from jscheid/master
    
    Fix incorrect re-throwing of error condition


commit 4040ae07e002b8457a49f1db108084aa012a1503
Author: Julian Scheid <address@hidden>
Date:   Sun Aug 5 02:07:56 2012 +0200

    Add test case for bugfix in 8513a7e38d7bf3538d235668ec16081cbd561460.

diff --git a/websocket-test.el b/websocket-test.el
index 85e4cb8..c20dab0 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -360,7 +360,12 @@
                                        (substring websocket-frames 0 2)))
       (should open-callback-called)
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
-      (should (equal (list frame2 frame1) processed-frames)))))
+      (should (equal (list frame2 frame1) processed-frames)))
+    (flet ((websocket-ready-state (websocket) 'connecting)
+           (websocket-close (websocket)))
+      (should (equal "Bad HTTP response code while opening websocket 
connection: 500"
+                     (car (cdr (should-error
+                                (websocket-outer-filter fake-ws "HTTP/1.1 
500\r\n\r\n")))))))))
 
 (ert-deftest websocket-outer-filter-bad-connection ()
   (let* ((on-open-calledp)

commit 8513a7e38d7bf3538d235668ec16081cbd561460
Author: Julian Scheid <address@hidden>
Date:   Sun Aug 5 01:05:28 2012 +0200

    Fix incorrect re-throwing of error condition.
    
    This was passing a cons cell as the first argument to `error', which
    expects a format string and thus throws an error itself.  Use the
    re-throw idiom suggested by
    
http://www.gnu.org/software/emacs/manual/html_node/elisp/Handling-Errors.html#index-condition_002dcase-578
    instead.
    
    NB: at first glance, `(error (cdr err))' is preferable as it is more
    succinct.  However, the generic form will keep working should the
    CONDITION-NAME in the condition-case form ever be changed.

diff --git a/websocket.el b/websocket.el
index aa049d3..e9f8f8e 100644
--- a/websocket.el
+++ b/websocket.el
@@ -582,7 +582,7 @@ connection is invalid, the connection will be closed."
             (websocket-verify-headers websocket text))
         (error
          (websocket-close websocket)
-         (error err)))
+         (signal (car err) (cdr err))))
       (setf (websocket-ready-state websocket) 'open)
       (websocket-try-callback 'websocket-on-open 'on-open websocket))
     (when (eq 'open (websocket-ready-state websocket))

commit 6525366e5557c7a53197856dd568063a2a1bba6c
Author: Leo Liu <address@hidden>
Date:   Sun Aug 5 01:15:43 2012 +0800

    Rename README to README.rst

diff --git a/README b/README.rst
similarity index 53%
rename from README
rename to README.rst
index 486954a..31cf7d3 100644
--- a/README
+++ b/README.rst
@@ -1,23 +1,24 @@
-Emacs Interface to command-line tool ack
-========================================
-
+==========================================
+ Emacs Interface to command-line tool ack
+==========================================
+ 
 From http://betterthangrep.com/
 
     ack is a tool like grep, designed for programmers with large trees of
     heterogeneous source code.
-    
+
     ack is written purely in Perl, and takes advantage of the power of
     Perl's regular expressions.
 
 Feature requests and bug reports are welcome. Thanks.
 
 Install
-----------
+=======
 
-Drop ack.el in the load-path and put (require 'ack) or (autoload 'ack
-"ack" nil t) in your .emacs.
+Place ``ack.el`` in the load-path and put ``(require 'ack)`` or
+``(autoload 'ack "ack" nil t)`` in your ``.emacs``.
 
 Usage
-----------
+=====
 
-M-x ack
+``M-x ack``

commit a98e56fbab64dc5c35f568420672c8f2e490551d
Author: Andrew Hyatt <address@hidden>
Date:   Wed Aug 1 19:21:58 2012 -0700

    Beginning of server functionality.  Completed header checking.

diff --git a/websocket-test.el b/websocket-test.el
index 85e4cb8..63a09ce 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -396,3 +396,34 @@
     (should-error (websocket-send ws
                                   (make-websocket-frame :opcode :close)))))
 
+(ert-deftest websocket-verify-client-headers ()
+  (let* ((http "HTTP/1.1")
+         (host "Host: authority")
+         (upgrade "Upgrade: websocket")
+         (key "Sec-Websocket-Key: key")
+         (version "Sec-Websocket-Version: 13")
+         (origin "Origin: origin")
+         (protocol "Sec-Websocket-Protocol: protocol")
+         (extensions1 "Sec-Websocket-Extensions: foo")
+         (extensions2 "Sec-Websocket-Extensions: bar; baz=2")
+         (all-required-headers (list host upgrade key version)))
+    ;; Test that all these headers are necessary
+    (should (equal
+             '(:key "key" :protocols ("protocol") :extensions ("foo" "bar; 
baz=2"))
+             (websocket-verify-client-headers
+              (mapconcat 'identity (append (list http "" protocol extensions1 
extensions2)
+                                           all-required-headers) "\r\n"))))
+    (should (websocket-verify-client-headers
+              (mapconcat 'identity
+                         (mapcar 'upcase
+                                 (append (list http "" protocol extensions1 
extensions2)
+                                         all-required-headers)) "\r\n")))
+    (dolist (header all-required-headers)
+      (should-not (websocket-verify-client-headers
+                   (mapconcat 'identity (append (list http "")
+                                                (remove header 
all-required-headers))
+                              "\r\n"))))
+    (should-not (websocket-verify-client-headers
+                 (mapconcat 'identity (append (list "HTTP/1.0" "") 
all-required-headers)
+                            "\r\n")))))
+
diff --git a/websocket.el b/websocket.el
index aa049d3..840e7b8 100644
--- a/websocket.el
+++ b/websocket.el
@@ -77,13 +77,14 @@ server.
   on-close
   on-error
   server-extensions
+  (server-p nil :read-only t)
 
   ;; Other data - clients should not have to access this.
   (url (assert nil) :read-only t)
   (protocol nil :read-only t)
   (extensions nil :read-only t)
   (conn (assert nil) :read-only t)
-  (accept-string (assert nil))
+  accept-string
   (inflight-input nil))
 
 (defvar websocket-version "0.92.1"
@@ -441,6 +442,95 @@ websocket."
     (websocket-debug websocket "Websocket opened")
     websocket))
 
+(defun websocket-get-address (port)
+  "Get a non-loopback address to serve from."
+  (let ((net-addr
+         (block 'get-address
+           (dolist (interface (network-interface-list))
+             (when (not (member
+                         'loopback
+                         (nth 4 (network-interface-info (car interface)))))
+               (return-from 'get-address (cdr interface))))
+           (error "No non-loopback interface found"))))
+    (aset net-addr 4 port)
+    net-addr))
+
+(defun websocket-server-accept (server client message)
+  "Accept a new websocket connection from a client."
+  (message "Connected from %S: %s" client message)
+  (let ((ws (websocket-inner-create
+             :conn client
+             :on-open (or (process-get proc :on-open) 'identity)
+             :on-message (or (process-get proc :on-message) (lambda (ws 
frame)))
+             :on-error (or (process-get proc :on-error) 'identity)
+             :protocol (process-get proc :protocol)
+             :extensions (mapcar 'car (process-get proc :extensions)))))
+    (process-put client :websocket ws)
+    (set-process-filter client 'websocket-server-filter)))
+
+(defun websocket-verify-client-headers (output)
+  "Verify the headers from the WEBSOCKET client connection in OUTPUT.
+Unlike `websocket-verify-headers', this is a quieter routine.  We
+don't want to error due to a bad client, so we just print out
+messages and a plist containing `:key', the websocket key,
+`:protocols' and `:extensions'."
+  (block nil
+    (let ((case-fold-search t)
+          (plist))
+      (unless (string-match "^HTTP/1.1" output)
+        (message "Websocket client connection: HTTP/1.1 not found")
+        (return nil))
+      (unless (string-match "^Host: " output)
+        (message "Websocket client connection: Host header not found")
+        (return nil))
+      (unless (string-match "^Upgrade: websocket\r\n" output)
+        (message "Websocket client connection: Upgrade: websocket not found")
+        (return nil))
+      (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output)
+          (setq plist (plist-put plist :key (match-string 1 output)))
+        (message "Websocket client connect: No key sent")
+        (return nil))
+      (unless (string-match "^Sec-WebSocket-Version: 13" output)
+        (message "Websocket client connect: Websocket version 13 not found")
+        (return nil))
+      (when (string-match "^Sec-WebSocket-Protocol: \\([[:graph:]]+\\)\r\n" 
output)
+        (setq plist (plist-put plist :protocols (websocket-parse-repeated-field
+                                                 output
+                                                 "Sec-Websocket-Protocol"))))
+      (when (string-match "^Sec-WebSocket-Extensions: \\([[:graph:]]+\\)\r\n" 
output)
+        (setq plist (plist-put plist :extensions 
(websocket-parse-repeated-field
+                                                  output
+                                                  
"Sec-Websocket-Extensions"))))
+      plist)))
+
+(defun websocket-server-filter (process output)
+  (let ((ws (process-get process :websocket)))
+    (cond ((eq (websocket-ready-state ws) 'connecting)
+           ;; check for connection string
+           (when (string-match "\r\n\r\n" output)
+             (if (websocket-verify-client-headers ws output)
+                 (progn (setf (websocket-ready-state ws) 'open)
+                        (websocket-server-filter process output))
+               (message "Invalid client headers found in: %s" output)
+               (websocket-close ws))))
+          ((eq (websocket-ready-state ws) 'open)
+           ;; process ouput
+           )
+          ((eq (websocket-ready-state ws) 'closed)
+           (message "WARNING: Should not have received further input on closed 
websocket")))))
+
+(defun* websocket-server (port &rest plist)
+  "Open a websocket server on PORT."
+  (let* ((conn (make-network-process
+                :name (format "websocket server on port %d" port)
+                :server t
+                :family 'ipv4
+                :log 'websocket-server-accept
+                :plist plist
+                :host 'local
+                :service port
+                :local (websocket-get-address port))))))
+
 (defun websocket-create-headers (url key protocol extensions)
   "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS.
 These are defined as in `websocket-open'."
@@ -494,6 +584,19 @@ if not."
               (match-string 1 output)))
   t)
 
+(defun websocket-parse-repeated-field (output field)
+  "From header-containing OUTPUT, parse out the list from a
+possibly repeated field."
+  (let ((pos 0)
+        (extensions))
+    (while (and pos
+                (string-match (format "\r\n%s: \\(.*\\)\r\n" field)
+                              output pos))
+      (when (setq pos (match-end 1))
+        (setq extensions (append extensions (split-string
+                                             (match-string 1 output) ", ?")))))
+    extensions))
+
 (defun websocket-verify-headers (websocket output)
   "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
 The output is assumed to have complete headers.  This function
@@ -519,23 +622,18 @@ of populating the list of server extensions to WEBSOCKET."
                (format "\r\nSec-Websocket-Protocol: %s\r\n"
                        (websocket-protocol websocket)) output)
         (error "Incorrect or missing protocol returned by the server.")))
-    (let ((pos 0)
-          (extensions))
-      (while (and pos
-                  (string-match "\r\nSec-Websocket-Extensions: \\(.*\\)\r\n"
-                      output pos))
-        (when (setq pos (match-end 1))
-          (setq extensions (append extensions (split-string
-                                               (match-string 1 output) ", 
?")))))
-      (let ((extra-extensions))
-        (dolist (ext extensions)
-          (when (not (member
-                      (first (split-string ext "; ?"))
-                      (websocket-extensions websocket)))
-            (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
-        (when extra-extensions
-          (error "Non-requested extensions returned by server: %s"
-                 extra-extensions)))
+    (let* ((extensions (websocket-parse-repeated-field
+                        output
+                        "Sec-WebSocket-Extensions"))
+           (extra-extensions))
+      (dolist (ext extensions)
+        (when (not (member
+                    (first (split-string ext "; ?"))
+                    (websocket-extensions websocket)))
+          (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
+      (when extra-extensions
+        (error "Non-requested extensions returned by server: %s"
+               extra-extensions))
       (setf (websocket-server-extensions websocket) extensions)))
   ;; return true
   t)

commit aeda94490cfc4eb0063585253f707d4042d60ba6
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 28 23:48:11 2012 -0700

    Update the version to 0.92.1.

diff --git a/websocket.el b/websocket.el
index 2da3459..aa049d3 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication
-;; Version: 0.92
+;; Version: 0.92.1
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -86,7 +86,7 @@ server.
   (accept-string (assert nil))
   (inflight-input nil))
 
-(defvar websocket-version "0.92"
+(defvar websocket-version "0.92.1"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit 88718f04077c88362a2a690e1e32fdb11e522e8f
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 28 23:44:59 2012 -0700

    Fix the emacs 23 issue a different way, as suggested by Takafumi Arakaki.
    
    The previous fix did not sufficiently fix the problem, since 'tls
    could be loaded by emacs 23.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index ecea61f..bcd7468 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -1,6 +1,7 @@
 ;; Simple functional testing
 ;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
 
+(require 'tls)   ;; tests a particular bug we had on emacs 23
 (setq debug-on-error t)
 (require 'websocket)
 (eval-when-compile (require 'cl))
@@ -62,7 +63,7 @@
 ;; Remove server test, with wss ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(when (featurep 'tls)
+(when (>= (string-to-int (substring emacs-version 0 2)) 24)
   (message "Testing with wss://echo.websocket.org")
   (setq wstest-ws
         (websocket-open
diff --git a/websocket.el b/websocket.el
index 5a41fb9..2da3459 100644
--- a/websocket.el
+++ b/websocket.el
@@ -398,12 +398,12 @@ websocket."
                                   (url-port url-struct)))
                           (host (url-host url-struct))
                           (buf (get-buffer-create buf-name)))
-                       (if (featurep 'tls)
-                           (open-network-stream name buf host port :type type 
:nowait nil)
-                         (when (eq type "wss")
-                           (error
-                            "This version of emacs does not support tls, so 
cannot connect to secure websockets (wss)"))
-                         (open-network-stream name buf host port)))
+                       (if (eq type 'plain)
+                           (make-network-process :name name :buffer buf :host 
host
+                                                 :service port :nowait nil)
+                         (condition-case-no-debug nil
+                             (open-network-stream name buf host port :type 
type :nowait nil)
+                           (wrong-number-of-arguments (error "No wss support 
in this Emacs version.")))))
                  (error "Unknown protocol")))
          (websocket (websocket-inner-create
                      :conn conn

commit 77f761c9b1db777529656bd3f512ebe1a04b29ac
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 28 15:24:25 2012 -0700

    Update version number to 0.92.

diff --git a/websocket.el b/websocket.el
index 91c1c45..5a41fb9 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication
-;; Version: 0.91
+;; Version: 0.92
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -86,7 +86,7 @@ server.
   (accept-string (assert nil))
   (inflight-input nil))
 
-(defvar websocket-version "0.91"
+(defvar websocket-version "0.92"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit 002c8b5728625454c4f271695db21a1f6239b6bd
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 28 15:23:14 2012 -0700

    Handle pongs and other random input.
    
    Random input does not yet signal an error, right now it is just ignored.

diff --git a/websocket.el b/websocket.el
index 30d3124..91c1c45 100644
--- a/websocket.el
+++ b/websocket.el
@@ -332,7 +332,7 @@ the frame finishes.  If the frame is not completed, return 
NIL."
                                          (+ 5 (cdr payload-len)))))
              (websocket-mask masking-key unmasked-payload))
          unmasked-payload)
-       :length payload-end
+       :length (if payloadp payload-end 1)
        :completep (> fin 0)))))
 
 (defun websocket-default-error-handler (websocket type err)
@@ -499,7 +499,6 @@ if not."
 The output is assumed to have complete headers.  This function
 will either return t or call `error'.  This has the side-effect
 of populating the list of server extensions to WEBSOCKET."
-  (websocket-debug websocket "Checking headers: %s" output)
   (let ((accept-string
          (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
     (websocket-debug websocket "Checking for accept header: %s" accept-string)
@@ -558,7 +557,8 @@ has connection termination."
              (lambda () (websocket-send lex-ws
                                    (make-websocket-frame :opcode 'pong 
:completep t))))
             ((eq opcode 'close)
-             (lambda () (delete-process (websocket-conn lex-ws))))))))
+             (lambda () (delete-process (websocket-conn lex-ws))))
+            (t (lambda ()))))))
 
 (defun websocket-outer-filter (websocket output)
   "Filter the WEBSOCKET server's OUTPUT.

commit eef37baf475fa8311176ff80220c5f7c0a502c13
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 28 15:20:02 2012 -0700

    Fix emacs 23 compatibility, and make it an explicit goal in the README

diff --git a/README.org b/README.org
index 4a425cb..b9c879a 100644
--- a/README.org
+++ b/README.org
@@ -6,6 +6,9 @@ to write apps that use websockets, and is not useful by itself.
 An example of how to use the library is in the
 
[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]]
 file.
 
+This library is compatible with emacs 23 and 24, although only emacs
+24 support secure websockets.
+
 * Version
 
 ** Version 1.0 requiements
@@ -23,7 +26,7 @@ the EIEIO branch).  Please send us any feedback about the API.
 Each version that is released should be checked with this checklist:
 
 - [ ] All ert test passing
-- [ ] Functional test passing
+- [ ] Functional test passing on emacs 23 and 24
 - [ ] websocket.el byte compiling cleanly
 
 * Existing clients:
diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index bf8fc35..ecea61f 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -1,6 +1,7 @@
 ;; Simple functional testing
 ;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
 
+(setq debug-on-error t)
 (require 'websocket)
 (eval-when-compile (require 'cl))
 
@@ -61,28 +62,28 @@
 ;; Remove server test, with wss ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(message "Testing with wss://echo.websocket.org")
+(when (featurep 'tls)
+  (message "Testing with wss://echo.websocket.org")
+  (setq wstest-ws
+        (websocket-open
+         "wss://echo.websocket.org"
+         :on-open (lambda (websocket)
+                    (message "Websocket opened"))
+         :on-message (lambda (websocket frame)
+                       (push (websocket-frame-payload frame) wstest-msgs)
+                       (message "ws frame: %S" (websocket-frame-payload 
frame)))
+         :on-close (lambda (websocket)
+                     (message "Websocket closed")
+                     (setq wstest-closed t)))
+        wstest-msgs nil)
+  (sleep-for 0.3)
+  (assert (websocket-openp wstest-ws))
+  (assert (null wstest-msgs))
+  (websocket-send-text wstest-ws "Hi!")
+  (sleep-for 0.1)
+  (assert (equal (car wstest-msgs) "Hi!"))
+  (websocket-close wstest-ws)
+  
+  (message "\nAll tests passed!\n"))
 
-(setq wstest-ws
-  (websocket-open
-   "wss://echo.websocket.org"
-   :on-open (lambda (websocket)
-              (message "Websocket opened"))
-   :on-message (lambda (websocket frame)
-                 (push (websocket-frame-payload frame) wstest-msgs)
-                 (message "ws frame: %S" (websocket-frame-payload frame)))
-   :on-close (lambda (websocket)
-               (message "Websocket closed")
-               (setq wstest-closed t)))
-  wstest-msgs nil)
-
-(sleep-for 0.1)
-(assert (websocket-openp wstest-ws))
-(assert (null wstest-msgs))
-(websocket-send-text wstest-ws "Hi!")
-(sleep-for 0.1)
-(assert (equal (car wstest-msgs) "Hi!"))
-(websocket-close wstest-ws)
-
-(message "\nAll tests passed!\n")
 
diff --git a/websocket.el b/websocket.el
index c0526b6..30d3124 100644
--- a/websocket.el
+++ b/websocket.el
@@ -391,17 +391,19 @@ websocket."
          (coding-system-for-read 'binary)
          (coding-system-for-write 'binary)
          (conn (if (member (url-type url-struct) '("ws" "wss"))
-                   (open-network-stream name (get-buffer-create buf-name)
-                                        (url-host url-struct)
-                                        (if (= 0 (url-port url-struct))
-                                                     (if (equal
-                                                          (url-type 
url-struct) "ws")
-                                                         80 443)
-                                                   (url-port url-struct))
-                                        :type (if (equal (url-type url-struct) 
"ws")
-                                                  'plain
-                                                'tls)
-                                        :nowait nil)
+                   (let* ((type (if (equal (url-type url-struct) "ws")
+                                    'plain 'tls))
+                          (port (if (= 0 (url-port url-struct))
+                                    (if (eq type 'tls) 443 80)
+                                  (url-port url-struct)))
+                          (host (url-host url-struct))
+                          (buf (get-buffer-create buf-name)))
+                       (if (featurep 'tls)
+                           (open-network-stream name buf host port :type type 
:nowait nil)
+                         (when (eq type "wss")
+                           (error
+                            "This version of emacs does not support tls, so 
cannot connect to secure websockets (wss)"))
+                         (open-network-stream name buf host port)))
                  (error "Unknown protocol")))
          (websocket (websocket-inner-create
                      :conn conn

commit b8bbe207d2f426fbd9e034c1f65cc45bc6af7ec3
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jul 24 09:33:24 2012 +0200

    (ioccur-print-results): Fix setting of case-fold-search.

diff --git a/ioccur.el b/ioccur.el
index 395d587..d53b04b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -309,7 +309,8 @@ Special commands:
   (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
     (let ((case-fold-search (case ioccur-case-fold-search
-                              (smart (if (string-match "[A-Z]" regexp) nil t))
+                              (smart (let ((case-fold-search nil))
+                                       (if (string-match "[A-Z]" regexp) nil 
t)))
                               (t ioccur-case-fold-search))))
       (save-excursion
         (goto-char (point-min))

commit f9664738bc043b20c27b9e7d6560759233d96522
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jul 24 06:48:31 2012 +0200

    (ioccur-case-fold-search): Provide smart case-fold-search in ioccur.

diff --git a/ioccur.el b/ioccur.el
index 8821c51..395d587 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -140,9 +140,20 @@ it slow down the start of ioccur at first time on large 
buffers."
   :group 'ioccur
   :type 'boolean)
 
+(defcustom ioccur-case-fold-search 'smart
+  "Add 'smart' option to `case-fold-search'.
+When smart is enabled, Ignore case in the search strings
+if pattern contains no uppercase characters.
+Otherwise, with a nil or t value, the behavior is same as
+`case-fold-search'.
+Default value is smart, other possible values are nil and t."
+  :group 'ioccur
+  :type 'symbol)
+
 (defvar ioccur-read-char-or-event-skip-read-key nil
   "Force not using `read-key' to read input in minibuffer even if bounded.
-Set it to non--nil if menu disapear or if keys are echoing in minibuffer.")
+Set it to non--nil if menu disapear or if keys are echoing in minibuffer.
+Deprecated, should be used only in old Emacs versions.")
 
 ;;; Faces.
 (defface ioccur-overlay-face
@@ -297,21 +308,24 @@ Special commands:
   "Print in `ioccur-buffer' lines matching REGEXP in `ioccur-current-buffer'."
   (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
-    (save-excursion
-      (goto-char (point-min))
-      (loop
-         while (not (eobp))
-         ;; We need to read also C-g from here
-         ;; Because when loop is started `ioccur-read-search-input'
-         ;; will read key only when loop is finished
-         ;; and we have no chance to exit loop.
-         when quit-flag do (setq ioccur-quit-flag t) and return nil
-         for count from 0
-         when (funcall ioccur-search-function regexp (point-at-eol) t)
-         do (ioccur-print-line
-             (buffer-substring (point-at-bol) (point-at-eol))
-             count (match-string 0) regexp)
-         do (forward-line 1)))))
+    (let ((case-fold-search (case ioccur-case-fold-search
+                              (smart (if (string-match "[A-Z]" regexp) nil t))
+                              (t ioccur-case-fold-search))))
+      (save-excursion
+        (goto-char (point-min))
+        (loop
+              while (not (eobp))
+              ;; We need to read also C-g from here
+              ;; Because when loop is started `ioccur-read-search-input'
+              ;; will read key only when loop is finished
+              ;; and we have no chance to exit loop.
+              when quit-flag do (setq ioccur-quit-flag t) and return nil
+              for count from 0
+              when (funcall ioccur-search-function regexp (point-at-eol) t)
+              do (ioccur-print-line
+                  (buffer-substring (point-at-bol) (point-at-eol))
+                  count (match-string 0) regexp)
+              do (forward-line 1))))))
 
 
 (defun ioccur-print-match (str &optional all)

commit e9b77128b33d0403e09ffd278447e483ce9b125f
Author: Andrew Hyatt <address@hidden>
Date:   Mon Jul 23 18:10:45 2012 -0700

    Set debug-on-error to the value of websocket-callback-debug-on-error,
    which is less confusing.  Suggested by Takafumi Arakaki.

diff --git a/websocket.el b/websocket.el
index 054e6a5..c0526b6 100644
--- a/websocket.el
+++ b/websocket.el
@@ -155,7 +155,8 @@ If an error happens, it is handled according to
   ;; I'm not sure that's the case.  We can't do it as a macro, since
   ;; we want it to change whenever websocket-callback-debug-on-error
   ;; changes.
-  (let ((args rest))
+  (let ((args rest)
+        (debug-on-error websocket-callback-debug-on-error))
     (push websocket args)
     (if websocket-callback-debug-on-error
         (condition-case err

commit f72863163f32877d837dcacf1f3a9ce106af6493
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 21 23:44:16 2012 -0700

    Add variable websocket-callback-debug-on-error.
    
    This also adds a function to wrap all callbacks, which uses
    websocket-callback-debug-on-error to invoke the debugger if requested.

diff --git a/websocket.el b/websocket.el
index f0de18e..054e6a5 100644
--- a/websocket.el
+++ b/websocket.el
@@ -103,6 +103,12 @@ Do not change unless the RFC changes.")
 This is recommended to be true, and some servers will refuse to
 communicate with unmasked clients.")
 
+(defvar websocket-callback-debug-on-error nil
+  "If true, when an error happens in a client callback, invoke the debugger.
+Having this on can cause issues with missing frames if the debugger is
+exited by quitting instead of continuing, so it's best to have this set
+to `nil' unless it is especially needed.")
+
 (defmacro websocket-document-function (function docstring)
   "Document FUNCTION with DOCSTRING.  Use this for defstruct accessor etc."
   (declare (indent defun)
@@ -140,6 +146,27 @@ See `websocket-open' for details.
       (aset s i (random 256)))
     s))
 
+(defun websocket-try-callback (websocket-callback callback-type websocket
+                                                  &rest rest)
+  "Invoke function WEBSOCKET-CALLBACK with WEBSOCKET and REST args.
+If an error happens, it is handled according to
+`websocket-callback-debug-on-error'."
+  ;; This looks like it should be able to done more efficiently, but
+  ;; I'm not sure that's the case.  We can't do it as a macro, since
+  ;; we want it to change whenever websocket-callback-debug-on-error
+  ;; changes.
+  (let ((args rest))
+    (push websocket args)
+    (if websocket-callback-debug-on-error
+        (condition-case err
+            (apply (funcall websocket-callback websocket) args)
+          ((debug error) (funcall (websocket-on-error websocket)
+                                  websocket callback-type err)))
+      (condition-case err
+          (apply (funcall websocket-callback websocket) args)
+        (error (funcall (websocket-on-error websocket) websocket
+                        callback-type err))))))
+
 (defun websocket-genkey ()
   "Generate a key suitable for the websocket handshake."
   (base64-encode-string (websocket-genbytes 16)))
@@ -348,9 +375,10 @@ a symbol as the second argument either `on-open', 
`on-message',
 or `on-close', and the error as the third argument. Do NOT
 rethrow the error, or else you may miss some websocket messages.
 You similarly must not generate any other errors in this method.
-In case you want to debug errors, a call to the `debug' function
-in the callback method will enter the debugger.  If not
-specified, `websocket-default-error-handler' is used.
+If you want to debug errors, set
+`websocket-callback-debug-on-error' to `t', but this also can be
+dangerous is the debugger is quit out of.  If not specified,
+`websocket-default-error-handler' is used.
 
 For each of these event handlers, the client code can store
 arbitrary data in the `client-data' slot in the returned
@@ -397,11 +425,7 @@ websocket."
          (websocket-debug websocket
                           "State change to %s" change)
          (unless (eq 'closed (websocket-ready-state websocket))
-           (condition-case err
-               (funcall (websocket-on-close websocket)
-                        websocket)
-               (error (funcall (websocket-on-error websocket)
-                               websocket 'on-close err)))))))
+           (websocket-try-callback 'websocket-on-close 'on-close websocket)))))
     (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"
@@ -525,10 +549,8 @@ has connection termination."
     (lexical-let ((lex-ws websocket)
                   (lex-frame frame))
       (cond ((memq opcode '(continuation text binary))
-             (lambda () (condition-case err
-                       (funcall (websocket-on-message websocket) lex-ws 
lex-frame)
-                     (error (funcall (websocket-on-error websocket)
-                                     websocket 'on-message err)))))
+             (lambda () (websocket-try-callback 'websocket-on-message 
'on-message
+                                           lex-ws lex-frame)))
             ((eq opcode 'ping)
              (lambda () (websocket-send lex-ws
                                    (make-websocket-frame :opcode 'pong 
:completep t))))
@@ -559,9 +581,7 @@ connection is invalid, the connection will be closed."
          (websocket-close websocket)
          (error err)))
       (setf (websocket-ready-state websocket) 'open)
-      (condition-case err
-          (funcall (websocket-on-open websocket) websocket)
-        (error (funcall (websocket-on-error websocket) websocket 'on-open 
err))))
+      (websocket-try-callback 'websocket-on-open 'on-open websocket))
     (when (eq 'open (websocket-ready-state websocket))
       (unless start-point (setq start-point 0))
       (let ((current-frame))

commit 7031812ba83c01246205b30a11fc79e99a0a41ea
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 15 21:45:03 2012 -0400

    Update to version 0.91.
    
    Notably this version has:
      - support for wss sockets
      - support for 32-bit emacs
      - better error handling

diff --git a/README.org b/README.org
index bf2d9e9..4a425cb 100644
--- a/README.org
+++ b/README.org
@@ -8,14 +8,24 @@ An example of how to use the library is in the
 
 * Version
 
-This version should be usable, but should have the following
-requirements for a version 1.0:
+** Version 1.0 requiements
+This version should be usable, but needs the following:
 
-- Support for encrypted sockets.
 - 3 clients using this module.  Without this many clients, it's hard
   to be sure the API is right, or there isn't a hidden bug in the
   module.
 
+Notably, this project is experimenting with an eieio-based API (see
+the EIEIO branch).  Please send us any feedback about the API.
+
+** Version release checklist
+
+Each version that is released should be checked with this checklist:
+
+- [ ] All ert test passing
+- [ ] Functional test passing
+- [ ] websocket.el byte compiling cleanly
+
 * Existing clients:
 
 - [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]]
@@ -23,3 +33,4 @@ requirements for a version 1.0:
 If you are using this module for your own emacs package, please let me
 know by editing this file, adding your project, and sending a pull
 request to this repository.
+
diff --git a/websocket.el b/websocket.el
index 3f03cf6..f0de18e 100644
--- a/websocket.el
+++ b/websocket.el
@@ -5,7 +5,7 @@
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Keywords: Communication
-;; Version: 0.9
+;; Version: 0.91
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -86,7 +86,7 @@ server.
   (accept-string (assert nil))
   (inflight-input nil))
 
-(defvar websocket-version "0.9"
+(defvar websocket-version "0.91"
   "Version numbers of this version of websocket.el.")
 
 (defvar websocket-debug nil

commit 4fe753df26e46c55e65cebd82563eaa21b58ded7
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 15 21:44:37 2012 -0400

    Add a note about the debug function and its use in the on-error
    callback.

diff --git a/websocket.el b/websocket.el
index 4c3dfbc..3f03cf6 100644
--- a/websocket.el
+++ b/websocket.el
@@ -348,7 +348,9 @@ a symbol as the second argument either `on-open', 
`on-message',
 or `on-close', and the error as the third argument. Do NOT
 rethrow the error, or else you may miss some websocket messages.
 You similarly must not generate any other errors in this method.
-If not specified, `websocket-default-error-handler' is used.
+In case you want to debug errors, a call to the `debug' function
+in the callback method will enter the debugger.  If not
+specified, `websocket-default-error-handler' is used.
 
 For each of these event handlers, the client code can store
 arbitrary data in the `client-data' slot in the returned

commit 6da6686de57c149edcdd86c85dc95d3ca8e88a1f
Merge: dac0a43 56bffcd
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 15 17:35:49 2012 -0400

    Merge branch 'wss'


commit dac0a43c5314b510f1b281dc910ebc33500902ac
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 15 17:35:28 2012 -0400

    Remove unused error handling function.

diff --git a/websocket.el b/websocket.el
index 457f7c8..67afed3 100644
--- a/websocket.el
+++ b/websocket.el
@@ -443,12 +443,6 @@ These are defined as in `websocket-open'."
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
 
-(defun websocket-error (websocket msg &rest args)
-  "Report error message MSG."
-  (unless websocket-ignore-error
-    (apply 'message msg args))
-  (apply 'websocket-debug websocket msg args))
-
 (defun websocket-debug (websocket msg &rest args)
   "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
   (when websocket-debug

commit 56bffcdb508f932924a25bffc20f4736c52ef1ec
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 15 17:33:00 2012 -0400

    Add support for secure websockets.
    
    This is tested by additions to the functional test, using
    wss://echo.websocket.org.

diff --git a/README.org b/README.org
index dd3f40d..bf2d9e9 100644
--- a/README.org
+++ b/README.org
@@ -6,8 +6,6 @@ to write apps that use websockets, and is not useful by itself.
 An example of how to use the library is in the
 
[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]]
 file.
 
-Currently, this library only supports unencrypted websockets.
-
 * Version
 
 This version should be usable, but should have the following
@@ -23,5 +21,5 @@ requirements for a version 1.0:
 - [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]]
 
 If you are using this module for your own emacs package, please let me
-by editing this file, adding your project, and sending a pull request
-to this repository.
+know by editing this file, adding your project, and sending a pull
+request to this repository.
diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index bf9ced2..bf8fc35 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -4,6 +4,12 @@
 (require 'websocket)
 (eval-when-compile (require 'cl))
 
+;;;;;;;;;;;;;;;;;;;;;;;
+;; Local server test ;;
+;;;;;;;;;;;;;;;;;;;;;;;
+
+(message "Testing with local server")
+
 (setq websocket-debug t)
 
 (defvar wstest-server-buffer (get-buffer-create "*wstest-server*"))
@@ -50,3 +56,33 @@
 (assert (null (websocket-openp wstest-ws)))
 
 (stop-process wstest-server-proc)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Remove server test, with wss ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(message "Testing with wss://echo.websocket.org")
+
+(setq wstest-ws
+  (websocket-open
+   "wss://echo.websocket.org"
+   :on-open (lambda (websocket)
+              (message "Websocket opened"))
+   :on-message (lambda (websocket frame)
+                 (push (websocket-frame-payload frame) wstest-msgs)
+                 (message "ws frame: %S" (websocket-frame-payload frame)))
+   :on-close (lambda (websocket)
+               (message "Websocket closed")
+               (setq wstest-closed t)))
+  wstest-msgs nil)
+
+(sleep-for 0.1)
+(assert (websocket-openp wstest-ws))
+(assert (null wstest-msgs))
+(websocket-send-text wstest-ws "Hi!")
+(sleep-for 0.1)
+(assert (equal (car wstest-msgs) "Hi!"))
+(websocket-close wstest-ws)
+
+(message "\nAll tests passed!\n")
+
diff --git a/websocket.el b/websocket.el
index 457f7c8..013c44f 100644
--- a/websocket.el
+++ b/websocket.el
@@ -34,8 +34,6 @@
 ;; A callback is passed to `websocket-open' that will retrieve
 ;; websocket frames called from the websocket.  Websockets are
 ;; eventually closed with `websocket-close'.
-;;
-;; Currently secure websockets (with wss addresses) are not supported.
 
 (require 'bindat)
 (require 'url-parse)
@@ -361,17 +359,19 @@ websocket."
          (buf-name (format " *%s*" name))
          (coding-system-for-read 'binary)
          (coding-system-for-write 'binary)
-         (conn (if (equal (url-type url-struct) "ws")
-                   (make-network-process :name name
-                                         :buffer buf-name
-                                         :host (url-host url-struct)
-                                         :service (if (= 0 (url-port 
url-struct))
-                                                      80
-                                                    (url-port url-struct))
-                                         :nowait nil)
-                 (if (equal (url-type url-struct) "wss")
-                     (error "Not implemented yet")
-                   (error "Unknown protocol"))))
+         (conn (if (member (url-type url-struct) '("ws" "wss"))
+                   (open-network-stream name (get-buffer-create buf-name)
+                                        (url-host url-struct)
+                                        (if (= 0 (url-port url-struct))
+                                                     (if (equal
+                                                          (url-type 
url-struct) "ws")
+                                                         80 443)
+                                                   (url-port url-struct))
+                                        :type (if (equal (url-type url-struct) 
"ws")
+                                                  'plain
+                                                'tls)
+                                        :nowait nil)
+                 (error "Unknown protocol")))
          (websocket (websocket-inner-create
                      :conn conn
                      :url url
@@ -609,7 +609,7 @@ This will raise an error if the frame is illegal."
 connecting or open."
   (and websocket
        (not (eq 'close (websocket-ready-state websocket)))
-       (eq 'open (process-status (websocket-conn websocket)))))
+       (member (process-status (websocket-conn websocket)) '(open run))))
 
 (defun websocket-close (websocket)
   "Close WEBSOCKET and erase all the old websocket data."

commit db9ab33947c409b4ab88570e95ceca0985cc69fb
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 14 00:32:17 2012 -0400

    Fixed condition-case for websocket-on-close.

diff --git a/websocket.el b/websocket.el
index 6bb3173..457f7c8 100644
--- a/websocket.el
+++ b/websocket.el
@@ -395,7 +395,7 @@ websocket."
          (websocket-debug websocket
                           "State change to %s" change)
          (unless (eq 'closed (websocket-ready-state websocket))
-           (condition-case
+           (condition-case err
                (funcall (websocket-on-close websocket)
                         websocket)
                (error (funcall (websocket-on-error websocket)

commit f63c6546ddbf1e7711b540c96f0c9adb8615e449
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 14 00:29:05 2012 -0400

    Add one-error documentation to match the other on-* documentations.

diff --git a/websocket.el b/websocket.el
index d926560..6bb3173 100644
--- a/websocket.el
+++ b/websocket.el
@@ -129,6 +129,12 @@ See `websocket-open' for details.
 
 \(fn WEBSOCKET)")
 
+(websocket-document-function websocket-on-error
+  "Accessor for websocket on-error callback.
+See `websocket-open' for details.
+
+\(fn WEBSOCKET)")
+
 (defun websocket-genbytes (nbytes)
   "Generate NBYTES random bytes."
   (let ((s (make-string nbytes ?\s)))

commit f32de3dc93741ac13aed564aa1d0fe98baf6e57d
Merge: 14e94a4 29a0539
Author: Andrew Hyatt <address@hidden>
Date:   Fri Jul 13 21:27:29 2012 -0700

    Merge pull request #21 from tkf/document-function
    
    Document accessors such as on-open


commit 14e94a46039336952def0b7ea7cee01a588938dc
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 14 00:19:32 2012 -0400

    Revamp how error processing works, increasing user control and
    resiliancy.
    
    Instead of a variable to control whether we debug or not, we now have
    a on-error callback that gets called on every error in a callback.
    
    Also, now all frame processing is done at once, after all incoming
    bytes have been processed.  This will decrease the chance of
    disruptions because of errors.  However, there can be no safe error
    when it is thrown, since if several frames are processed, and the
    first one throws an error, there is no mechanism to go back and
    process the rest.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index ff98153..bf9ced2 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -5,7 +5,6 @@
 (eval-when-compile (require 'cl))
 
 (setq websocket-debug t)
-(toggle-debug-on-error)
 
 (defvar wstest-server-buffer (get-buffer-create "*wstest-server*"))
 (defvar wstest-server-name "wstest-server")
@@ -24,7 +23,8 @@
    "ws://127.0.0.1:9999"
    :on-message (lambda (websocket frame)
                  (push (websocket-frame-payload frame) wstest-msgs)
-                 (message "ws frame: %S" (websocket-frame-payload frame)))
+                 (message "ws frame: %S" (websocket-frame-payload frame))
+                 (error "Test error (expected)"))
    :on-close (lambda (websocket) (setq wstest-closed t))))
 
 (defun wstest-pop-to-debug ()
@@ -36,9 +36,15 @@
 (assert (websocket-openp wstest-ws))
 
 (assert (null wstest-msgs))
+
 (websocket-send-text wstest-ws "Hi!")
+
 (sleep-for 0.1)
 (assert (equal (car wstest-msgs) "You said: Hi!"))
+(setf (websocket-on-error wstest-ws) (lambda (ws type err)))
+(websocket-send-text wstest-ws "Hi after error!")
+(sleep-for 0.1)
+(assert (equal (car wstest-msgs) "You said: Hi after error!"))
 
 (websocket-close wstest-ws)
 (assert (null (websocket-openp wstest-ws)))
diff --git a/websocket-test.el b/websocket-test.el
index 7737f36..85e4cb8 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -225,24 +225,40 @@
       (should (equal
                "hello"
                (progn
-                 (websocket-process-frame
-                  websocket
-                  (make-websocket-frame :opcode opcode :payload "hello"))
+                 (funcall (websocket-process-frame
+                   websocket
+                   (make-websocket-frame :opcode opcode :payload "hello")))
                  processed))))
     (setq sent nil)
     (flet ((websocket-send (websocket content) (setq sent content)))
       (should (equal
                (make-websocket-frame :opcode 'pong :completep t)
                (progn
-                 (websocket-process-frame websocket
-                                          (make-websocket-frame :opcode 'ping))
+                 (funcall (websocket-process-frame websocket
+                                           (make-websocket-frame :opcode 
'ping)))
                  sent))))
     (flet ((delete-process (conn) (setq deleted t)))
       (should (progn
-                (websocket-process-frame websocket
-                                         (make-websocket-frame :opcode 'close))
+                (funcall
+                 (websocket-process-frame websocket
+                                          (make-websocket-frame :opcode 
'close)))
                 deleted)))))
 
+(ert-deftest websocket-process-frame-error-handling ()
+  (let* ((error-called)
+         (websocket (websocket-inner-create
+                     :conn t :url t :accept-string t
+                     :on-message (lambda (websocket frame)
+                                   (message "In on-message")
+                                   (error "err"))
+                     :on-error (lambda (ws type err)
+                                 (should (eq 'on-message type))
+                                 (setq error-called t)))))
+    (funcall (websocket-process-frame websocket
+                                      (make-websocket-frame :opcode 'text
+                                                            :payload "hello")))
+    (should error-called)))
+
 (ert-deftest websocket-to-bytes ()
   ;; We've tested websocket-get-bytes by itself, now we can use it to
   ;; help test websocket-to-bytes.
@@ -316,7 +332,8 @@
                               (should (eq (websocket-ready-state websocket)
                                           'open))
                               (setq open-callback-called t)
-                              (error "Ignore me!"))))
+                              (error "Ignore me!"))
+                   :on-error (lambda (ws type err))))
          (processed-frames)
          (frame1 (make-websocket-frame :opcode 'text :payload "foo" :completep 
t
                                        :length 9))
@@ -327,8 +344,10 @@
           (concat
            (websocket-encode-frame frame1)
            (websocket-encode-frame frame2))))
-    (flet ((websocket-process-frame (websocket frame)
-                                    (push frame processed-frames))
+    (flet ((websocket-process-frame
+            (websocket frame)
+            (lexical-let ((frame frame))
+              (lambda () (push frame processed-frames))))
            (websocket-verify-response-code (output) t)
            (websocket-verify-headers (websocket output) t))
       (websocket-outer-filter fake-ws "Sec-")
@@ -360,56 +379,6 @@
          (should-not on-open-calledp)
          (should websocket-closed-calledp))))))
 
-(defun websocket-test-get-filtered-response-with-error
-  (frames &optional callback)
-  (let* ((filter-frames)
-         (websocket
-          (websocket-inner-create
-           :conn "fake-conn"
-           :on-message (lambda (websocket frame)
-                         (push frame filter-frames)
-                         (when callback (funcall callback)))
-           :on-close (lambda (not-called) (assert nil))
-           :url t :accept-string t))
-         err-list)
-    (dolist (frame frames)
-      (condition-case err
-          (websocket-process-frame websocket frame)
-        (error (push err err-list))))
-    (list (nreverse filter-frames) (nreverse err-list))))
-
-(defun websocket-test-get-filtered-response (frames)
-  (destructuring-bind (filter-frames err-list)
-      (websocket-test-get-filtered-response-with-error frames)
-    (assert (eq (length err-list) 0))
-    filter-frames))
-
-(ert-deftest websocket-filter-handle-error-in-filter ()
-  (let ((foo-frame (make-websocket-frame :opcode 'text
-                                   :payload "foo"
-                                   :completep t))
-        (bar-frame (make-websocket-frame :opcode 'text
-                                         :payload "bar"
-                                         :completep t)))
-    (destructuring-bind (filter-frames err-list)
-        (websocket-test-get-filtered-response-with-error
-         (list foo-frame bar-frame)
-         (lambda () (error "See if websocket can handle this")))
-      (should (equal filter-frames (list foo-frame bar-frame)))
-      (should (equal err-list nil)))
-    (destructuring-bind (filter-frames err-list)
-      (websocket-test-get-filtered-response-with-error
-       (list foo-frame bar-frame)
-       (lambda () "Raise another type of error" (/ 1 0)))
-    (should (equal filter-frames (list foo-frame bar-frame)))
-    (should (equal err-list nil)))
-    (destructuring-bind (filter-frames err-list)
-      (websocket-test-get-filtered-response-with-error
-       (list foo-frame bar-frame)
-       (lambda () (error "See if websocket can handle this")))
-    (should (equal filter-frames (list foo-frame bar-frame)))
-    (should (equal err-list nil)))))
-
 (ert-deftest websocket-send ()
   (let ((ws (websocket-inner-create :conn t :url t :accept-string t)))
     (flet ((websocket-ensure-connected (websocket))
diff --git a/websocket.el b/websocket.el
index f4e4582..21cb225 100644
--- a/websocket.el
+++ b/websocket.el
@@ -65,8 +65,8 @@ subprocess.  There may, in fact, be output data buffered,
 however, when the `on-message' or `close-callback' callbacks are
 called.
 
-`on-open', `on-message' and `on-close' are described in
-`websocket-open'.
+`on-open', `on-message', `on-close', and `on-error' are described
+in `websocket-open'.
 
 The `server-extensions' slot lists the extensions accepted by the
 server.
@@ -77,6 +77,7 @@ server.
   on-open
   on-message
   on-close
+  on-error
   server-extensions
 
   ;; Other data - clients should not have to access this.
@@ -95,9 +96,6 @@ server.
 The buffer is ` *websocket URL debug*' where URL is the
 URL of the connection.")
 
-(defvar websocket-ignore-error nil
-  "Set to true to suppress error messages.")
-
 (defconst websocket-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
   "The websocket GUID as defined in RFC 6455.
 Do not change unless the RFC changes.")
@@ -281,8 +279,13 @@ the frame finishes.  If the frame is not completed, return 
NIL."
        :length payload-end
        :completep (> fin 0)))))
 
+(defun websocket-default-error-handler (websocket type err)
+  "The default error handler used to handle errors in callbacks."
+  (message "Error found in callback `%S': %s" type (cdr err)))
+
 (defun* websocket-open (url &key protocol extensions (on-open 'identity)
-                            (on-message 'identity) (on-close 'identity))
+                            (on-message (lambda (w f))) (on-close 'identity)
+                            (on-error 'websocket-default-error-handler))
   "Open a websocket connection to URL, returning the `websocket' struct.
 The PROTOCOL argument is optional, and setting it will declare to
 the server that this client supports the protocol.  We will
@@ -311,14 +314,17 @@ The ON-CLOSE callback is called after the connection is 
closed, or
 failed to open.  It is called with the websocket as the only
 argument, and the return value is unused.
 
+The ON-ERROR callback is called when any of the other callbacks
+have an error.  It takes the websocket as the first argument, and
+a symbol as the second argument either `on-open', `on-message',
+or `on-close', and the error as the third argument. Do NOT
+rethrow the error, or else you may miss some websocket messages.
+You similarly must not generate any other errors in this method.
+If not specified, `websocket-default-error-handler' is used.
+
 For each of these event handlers, the client code can store
 arbitrary data in the `client-data' slot in the returned
-websocket. Errors from the callbacks will be ignored.  You should
-catch it in the callback function in order to recover from the
-error.  Errors not caught will be messaged using `messsage'
-function.  To suppress messaging errors, set
-`websocket-ignore-error' to t.  You can log errors by setting
-variable `websocket-debug' to t."
+websocket."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key (websocket-genkey))
@@ -342,6 +348,7 @@ variable `websocket-debug' to t."
                      :on-open on-open
                      :on-message on-message
                      :on-close on-close
+                     :on-error on-error
                      :protocol protocol
                      :extensions (mapcar 'car extensions)
                      :accept-string
@@ -358,12 +365,11 @@ variable `websocket-debug' to t."
          (websocket-debug websocket
                           "State change to %s" change)
          (unless (eq 'closed (websocket-ready-state websocket))
-           (condition-case err
+           (condition-case
                (funcall (websocket-on-close websocket)
                         websocket)
-             (error (websocket-error
-                     websocket
-                     "Got error from the op-close function: %s")))))))
+               (error (funcall (websocket-on-error websocket)
+                               websocket 'on-close err)))))))
     (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"
@@ -484,21 +490,24 @@ of populating the list of server extensions to WEBSOCKET."
 
 (defun websocket-process-frame (websocket frame)
   "Using the WEBSOCKET's filter and connection, process the FRAME.
-If the frame has a payload, the frame is passed to the filter
-slot of WEBSOCKET.  If the frame is a ping, we reply with a pong.
-If the frame is a close, we terminate the connection."
+This returns a lambda that should be executed when all frames have
+been processed.  If the frame has a payload, the lambda has the frame
+passed to the filter slot of WEBSOCKET.  If the frame is a ping,
+the lambda has a reply with a pong.  If the frame is a close, the lambda
+has connection termination."
   (let ((opcode (websocket-frame-opcode frame)))
-    (cond ((memq opcode '(continuation text binary))
-           (condition-case err
-               (funcall (websocket-on-message websocket) websocket frame)
-             (error (websocket-error websocket
-                                     "Got error from the on-message function: 
%s"
-                                     (error-message-string err)))))
-          ((eq opcode 'ping)
-           (websocket-send websocket
-                           (make-websocket-frame :opcode 'pong :completep t)))
-          ((eq opcode 'close)
-           (delete-process (websocket-conn websocket))))))
+    (lexical-let ((lex-ws websocket)
+                  (lex-frame frame))
+      (cond ((memq opcode '(continuation text binary))
+             (lambda () (condition-case err
+                       (funcall (websocket-on-message websocket) lex-ws 
lex-frame)
+                     (error (funcall (websocket-on-error websocket)
+                                     websocket 'on-message err)))))
+            ((eq opcode 'ping)
+             (lambda () (websocket-send lex-ws
+                                   (make-websocket-frame :opcode 'pong 
:completep t))))
+            ((eq opcode 'close)
+             (lambda () (delete-process (websocket-conn lex-ws))))))))
 
 (defun websocket-outer-filter (websocket output)
   "Filter the WEBSOCKET server's OUTPUT.
@@ -509,7 +518,8 @@ connection is invalid, the connection will be closed."
   (let ((start-point)
         (end-point 0)
         (text (concat (websocket-inflight-input websocket) output))
-        (header-end-pos))
+        (header-end-pos)
+        (processing-queue))
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
     (when (and (eq 'connecting (websocket-ready-state websocket))
@@ -525,18 +535,18 @@ connection is invalid, the connection will be closed."
       (setf (websocket-ready-state websocket) 'open)
       (condition-case err
           (funcall (websocket-on-open websocket) websocket)
-        (error (websocket-error websocket
-                                "Got error from the on-open function: %s"
-                                (error-message-string err)))))
+        (error (funcall (websocket-on-error websocket) websocket 'on-open 
err))))
     (when (eq 'open (websocket-ready-state websocket))
       (unless start-point (setq start-point 0))
       (let ((current-frame))
         (while (and (setq current-frame (websocket-read-frame
                                          (substring text start-point))))
-          (websocket-process-frame websocket current-frame)
+          (push (websocket-process-frame websocket current-frame) 
processing-queue)
           (incf start-point (websocket-frame-length current-frame)))))
     (setf (websocket-inflight-input websocket)
-        (substring text (or start-point 0)))))
+        (substring text (or start-point 0)))
+    (dolist (to-process (nreverse processing-queue))
+      (funcall to-process))))
 
 (defun websocket-send-text (websocket text)
   "To the WEBSOCKET, send TEXT as a complete frame."
@@ -595,7 +605,8 @@ connecting or open."
                     :extensions (websocket-extensions websocket)
                     :on-open (websocket-on-open websocket)
                     :on-message (websocket-on-message websocket)
-                    :on-close (websocket-on-close websocket))))
+                    :on-close (websocket-on-close websocket)
+                    :on-error (websocket-on-error websocket))))
 
 (provide 'websocket)
 

commit 29a0539625ff000d8594b4d20959d9cb806583e7
Author: Takafumi Arakaki <address@hidden>
Date:   Fri Jul 13 19:18:46 2012 +0200

    Minor fix on websocket-open docstring

diff --git a/websocket.el b/websocket.el
index 9085145..119dd49 100644
--- a/websocket.el
+++ b/websocket.el
@@ -320,7 +320,7 @@ EXTENSIONS can be NIL if none are in use.  An example value 
would
 be '(\"deflate-stream\" . (\"mux\" \"max-channels=4\")).
 
 Optionally you can specify
-ON_OPEN, ON-MESSAGE and ON-CLOSE callbacks as well.
+ON-OPEN, ON-MESSAGE and ON-CLOSE callbacks as well.
 
 The ON-OPEN callback is called after the connection is
 established with the websocket as the only argument.  The return

commit e0f566b2eab3dd39489f9a73c1cf812db52f9b87
Author: Takafumi Arakaki <address@hidden>
Date:   Fri Jul 13 19:18:19 2012 +0200

    Document accessors such as on-open

diff --git a/websocket.el b/websocket.el
index f4e4582..9085145 100644
--- a/websocket.el
+++ b/websocket.el
@@ -107,6 +107,30 @@ Do not change unless the RFC changes.")
 This is recommended to be true, and some servers will refuse to
 communicate with unmasked clients.")
 
+(defmacro websocket-document-function (function docstring)
+  "Document FUNCTION with DOCSTRING.  Use this for defstruct accessor etc."
+  (declare (indent defun)
+           (doc-string 2))
+  `(put ',function 'function-documentation ,docstring))
+
+(websocket-document-function websocket-on-open
+  "Accessor for websocket on-open callback.
+See `websocket-open' for details.
+
+\(fn WEBSOCKET)")
+
+(websocket-document-function websocket-on-message
+  "Accessor for websocket on-message callback.
+See `websocket-open' for details.
+
+\(fn WEBSOCKET)")
+
+(websocket-document-function websocket-on-close
+  "Accessor for websocket on-close callback.
+See `websocket-open' for details.
+
+\(fn WEBSOCKET)")
+
 (defun websocket-genbytes (nbytes)
   "Generate NBYTES random bytes."
   (let ((s (make-string nbytes ?\s)))

commit f8cb9c52614e0a8e477f1ac557585ed950246c9b
Author: Dmitry Gutov <address@hidden>
Date:   Fri Jul 13 07:43:38 2012 +0400

    Fix #58

diff --git a/js2-mode.el b/js2-mode.el
index 292d251..e2c2796 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10636,9 +10636,10 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
         (unless interrupted-p
           (setq js2-mode-parse-timer nil))))))
 
-(defun js2-mode-show-node ()
+(defun js2-mode-show-node (event)
   "Debugging aid:  highlight selected AST node on mouse click."
-  (interactive)
+  (interactive "e")
+  (mouse-set-point event)
   (let ((node (js2-node-at-point))
         beg
         end)
@@ -10659,6 +10660,8 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                      (js2-node-short-name (js2-node-parent node))
                    "nil"))))))
 
+(put 'js2-mode-show-node 'CUA 'move)
+
 (defun js2-mode-hide-overlay (&optional p1 p2)
   "Remove the debugging overlay when the point moves.
 P1 and P2 are the old and new values of point, respectively."

commit ffd6783e8a242e8bb29d18394cde3b0dd419d5a7
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Jul 11 06:15:18 2012 +0200

    Fix header according to Elpa, fix url. no code change.

diff --git a/ioccur.el b/ioccur.el
index fcb0165..8821c51 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -1,15 +1,12 @@
-;;; ioccur.el --- Incremental occur.
+;;; ioccur.el --- Incremental occur
 
-;; Author: Thierry Volpiatto <thierry dot volpiatto at gmail dot com>
-
-;; Copyright (C) 2010~2011 Thierry Volpiatto, all rights reserved.
+;; Copyright (C) 2010-2012  Free Software Foundation, Inc.
 
+;; Author: Thierry Volpiatto <thierry dot volpiatto at gmail dot com>
+;; X-URL: https://github.com/thierryvolpiatto/ioccur
+;; Version: 2.4
 ;; Compatibility: GNU Emacs >=22.3
 
-;; X-URL: http://mercurial.intuxication.org/hg/ioccur
-
-;; This file is not part of GNU Emacs.
-
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
 ;; published by the Free Software Foundation; either version 3, or
@@ -21,9 +18,7 @@
 ;; General Public License for more details.
 ;; 
 ;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING.  If not, write to
-;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
-;; Floor, Boston, MA 02110-1301, USA.
+;; along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 ;;; Install:
 ;;
@@ -38,20 +33,19 @@
 
 ;;; Commentary:
 ;;
-;; This package provide similar functionality as occur but is incremental.
+;; This package provides the command M-x ioccur, which is similar to
+;; M-x occur, except that it is incremental.
 ;;
-;; You can jump and quit to an occurence or jump
-;; and save the search buffer (ioccur-buffer) for further use.
-;; It is possible to toggle literal and regexp searching while running.
-;; It is auto documented both in mode-line and tooltip.
-;; It have its own history `ioccur-history' which is a real ring.
-;; etc...
+;; You can jump and quit to an occurrence, or jump and save the search
+;; buffer (ioccur-buffer) for further use.  You can toggle literal and
+;; regexp searching while running.  It is auto documented both in
+;; mode-line and tooltip.  It has its own history, `ioccur-history',
+;; which is a real ring.
 ;;
-;; To save `ioccur-history', use desktop, adding that to your .emacs:
-;; (add-to-list 'desktop-globals-to-save 'ioccur-history)
+;; To save `ioccur-history' via the Desktop package, add this to your
+;; init file (see (info "(emacs) Saving Emacs Sessions") for details):
 ;;
-;; For more info See:
-;; [EVAL] (info "(emacs) saving emacs sessions")
+;; (add-to-list 'desktop-globals-to-save 'ioccur-history)
 
 ;;; Code:
 (require 'derived)

commit 620610cdc7b199c10e6da049672f19879d22f247
Merge: cf885f0 39f1f28
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jul 8 21:47:13 2012 -0700

    Merge pull request #19 from tkf/test-32bit
    
    Force test to pass in 32-bit Emacs


commit 39f1f287fa9f9331f3a4ae580c7d7dc716aad035
Author: Takafumi Arakaki <address@hidden>
Date:   Mon Jul 9 03:00:32 2012 +0200

    Force test to pass in 32-bit Emacs

diff --git a/websocket-test.el b/websocket-test.el
index 8eb27ef..7737f36 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -45,11 +45,16 @@
   "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"
   "'Hello' masked string example, taken from the RFC.")
 
+(defconst websocket-test-64-bit-p
+  (calc-eval '("2^32 <= $") 'pred most-positive-fixnum))
+
 (ert-deftest websocket-get-bytes ()
   (should (equal #x5 (websocket-get-bytes "\x5" 1)))
   (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
-  (should (equal #x100000001
-                 (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)))
+  (let ((f (lambda () (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8))))
+    (if websocket-test-64-bit-p
+        (should (equal #x100000001 (funcall f)))
+      (should-error (funcall f))))
   (should-error (websocket-get-bytes "\x0\x0\x0" 3))
   (should-error (websocket-get-bytes "\x0" 2)))
 
@@ -243,7 +248,10 @@
   ;; help test websocket-to-bytes.
   (should (equal 30 (websocket-get-bytes (websocket-to-bytes 30 1) 1)))
   (should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
-  (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
+  (let ((f (lambda () (websocket-to-bytes 70000 8))))
+    (if websocket-test-64-bit-p
+        (should (equal 70000 (websocket-get-bytes (funcall f) 8)))
+      (should-error (funcall f))))
   (should-error (websocket-to-bytes 30 3))
   (should-error (websocket-to-bytes 300 1))
   ;; I'd like to test the error for 32-byte systems on 8-byte lengths,
@@ -259,7 +267,7 @@
              websocket-test-hello
              (websocket-encode-frame
               (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
-    (dolist (len '(200 70000))
+    (dolist (len (if websocket-test-64-bit-p '(200 70000) '(200 60000)))
       (let ((long-string (make-string len ?x)))
         (should (equal long-string
                        (websocket-frame-payload

commit cf885f0eb3bfd8eda973aa4b5e89ec3bb235b01c
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 7 20:38:55 2012 -0400

    Fix issue on < 64-bit systems in packing an 8 byte value.
    
    This sends a clear error of what the issue is only when we attempt to
    pack that many bytes.  Parsing of this method should now work even on
    32 bit systems.

diff --git a/websocket-test.el b/websocket-test.el
index 3ea37a6..8eb27ef 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -245,7 +245,11 @@
   (should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
   (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
   (should-error (websocket-to-bytes 30 3))
-  (should-error (websocket-to-bytes 300 1)))
+  (should-error (websocket-to-bytes 300 1))
+  ;; I'd like to test the error for 32-byte systems on 8-byte lengths,
+  ;; but elisp does not allow us to temporarily set constants such as
+  ;; most-positive-fixnum.
+  )
 
 (ert-deftest websocket-encode-frame ()
   ;; We've tested websocket-read-frame, now we can use that to help
diff --git a/websocket.el b/websocket.el
index 549d6be..f4e4582 100644
--- a/websocket.el
+++ b/websocket.el
@@ -156,9 +156,16 @@ NBYTES much be a power of 2, up to 8."
       (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
              val nbytes))
   (if (= nbytes 8)
-      (bindat-pack `((:val vec 2 u32))
-                   `((:val . [,(/ val 4294967296)
-                              ,(mod val 4294967296)])))
+      (progn
+        (when (calc-eval "$ < 4294967296" 'pred most-positive-fixnum)
+          (error "Could not send an 8-byte value on this version of emacs.
+A 64-bit version of emacs may solve your problem."))
+        ;; Need to use calc even though at this point things are manageable,
+        ;; since some emacs cannot parse the value 4294967296, even if
+        ;; they never evaluate it.
+        (bindat-pack `((:val vec 2 u32))
+                     `((:val . [,(calc-eval "floor($ / 4294967296)" 'raw val)
+                                ,(calc-eval "$ % 4294967296" 'raw val)]))))
     (bindat-pack
      `((:val ,(cond ((= nbytes 1) 'u8)
                     ((= nbytes 2) 'u16)

commit 559f84b002d0ee1d16102c063b408e9b0eb66d8e
Merge: 89b9afe 4569194
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jul 7 16:33:30 2012 -0700

    Merge pull request #16 from tkf/websocket-version
    
    Add a variable websocket-version


commit 95ed2b816d37c6b204df32316f2a0e998bc7b7a8
Merge: 5c6135d 3ee8493
Author: Dmitry Gutov <address@hidden>
Date:   Fri Jul 6 04:22:25 2012 +0400

    Merge branch 'master' into emacs24

diff --cc js2-mode.el
index 41283d9,292d251..5ca1557
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -9727,13 -9984,14 +9727,14 @@@ to a multiline declaration statement.  
                (backward-sexp)
              (scan-error (setq at-opening-bracket t))))
          (when (looking-at js2-declaration-keyword-re)
-           (- (1+ (match-end 0)) (point-at-bol)))))))
+           (goto-char (match-end 0))
+           (1+ (current-column)))))))
  
  (defun js2-ctrl-statement-indentation ()
 -  "Returns the proper indentation of the current line if it
 -starts the body of a control statement without braces, else
 -returns nil."
 -  (let (forward-sexp-function)  ; temporarily unbind it
 +  "Return the proper indentation of current line if it is a control statement.
 +Returns an indentation if this line starts the body of a control
 +statement without braces, else returns nil."
 +  (let (forward-sexp-function)
      (save-excursion
        (back-to-indentation)
        (when (and (not (js2-same-line (point-min)))

commit 3ee849316253121ec4ee51268bc814ab60d63b2f
Author: Dmitry Gutov <address@hidden>
Date:   Fri Jul 6 04:21:19 2012 +0400

    Fix #57

diff --git a/js2-mode.el b/js2-mode.el
index a2887e5..292d251 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9984,7 +9984,8 @@ to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
               (backward-sexp)
             (scan-error (setq at-opening-bracket t))))
         (when (looking-at js2-declaration-keyword-re)
-          (- (1+ (match-end 0)) (point-at-bol)))))))
+          (goto-char (match-end 0))
+          (1+ (current-column)))))))
 
 (defun js2-ctrl-statement-indentation ()
   "Returns the proper indentation of the current line if it

commit 89b9afe67bcada229e8023ccde3846b68a4999da
Author: Andrew Hyatt <address@hidden>
Date:   Thu Jul 5 15:39:26 2012 -0700

    Remove mapcan to remove runtime dependence on cl.

diff --git a/websocket.el b/websocket.el
index fe0c747..e78164a 100644
--- a/websocket.el
+++ b/websocket.el
@@ -459,13 +459,12 @@ of populating the list of server extensions to WEBSOCKET."
         (when (setq pos (match-end 1))
           (setq extensions (append extensions (split-string
                                                (match-string 1 output) ", 
?")))))
-      (let ((extra-extensions
-             (mapcan (lambda (ext) (when (not
-                                     (member
-                                      (first (split-string ext "; ?"))
-                                      (websocket-extensions websocket)))
-                                (list (first (split-string ext "; ?")))))
-                     extensions)))
+      (let ((extra-extensions))
+        (dolist (ext extensions)
+          (when (not (member
+                      (first (split-string ext "; ?"))
+                      (websocket-extensions websocket)))
+            (add-to-list 'extra-extensions (first (split-string ext "; ?")))))
         (when extra-extensions
           (error "Non-requested extensions returned by server: %s"
                  extra-extensions)))

commit 4569194b089f11d3ae76b384752c65c2c8be6037
Author: Takafumi Arakaki <address@hidden>
Date:   Tue Jul 3 12:02:23 2012 +0200

    Add a variable websocket-version

diff --git a/websocket.el b/websocket.el
index fe0c747..a5aba6e 100644
--- a/websocket.el
+++ b/websocket.el
@@ -87,6 +87,9 @@ server.
   (accept-string (assert nil))
   (inflight-input nil))
 
+(defvar websocket-version "0.9"
+  "Version numbers of this version of websocket.el.")
+
 (defvar websocket-debug nil
   "Set to true to output debugging info to a per-websocket buffer.
 The buffer is ` *websocket URL debug*' where URL is the

commit a31f0a888d305a221f9262252e824adba5bddbc0
Author: Andrew Hyatt <address@hidden>
Date:   Mon Jul 2 23:10:10 2012 -0500

    Put version at 0.9.  Add info about the version to the README.org, as
    well as info about clients of this module.

diff --git a/README.org b/README.org
index c4fda04..dd3f40d 100644
--- a/README.org
+++ b/README.org
@@ -1,3 +1,4 @@
+* Description
 This is a elisp library for websocket clients to talk to websocket
 servers. This library is designed to be used by other library writers,
 to write apps that use websockets, and is not useful by itself.
@@ -6,3 +7,21 @@ An example of how to use the library is in the
 
[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]]
 file.
 
 Currently, this library only supports unencrypted websockets.
+
+* Version
+
+This version should be usable, but should have the following
+requirements for a version 1.0:
+
+- Support for encrypted sockets.
+- 3 clients using this module.  Without this many clients, it's hard
+  to be sure the API is right, or there isn't a hidden bug in the
+  module.
+
+* Existing clients:
+
+- [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]]
+
+If you are using this module for your own emacs package, please let me
+by editing this file, adding your project, and sending a pull request
+to this repository.
diff --git a/websocket.el b/websocket.el
index 56fd507..fe0c747 100644
--- a/websocket.el
+++ b/websocket.el
@@ -4,6 +4,8 @@
 ;;
 ;; Author: Andrew Hyatt <ahyatt at gmail dot com>
 ;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
+;; Keywords: Communication
+;; Version: 0.9
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as

commit 5c6135d76d3ea8daa6da4b3792ab542ab9827212
Merge: 441da8c 858b079
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 12:39:19 2012 +0400

    Merge branch 'master' into emacs24
    
    Conflicts:
        js2-mode.el

diff --cc js2-mode.el
index 7a7dfc3,a2887e5..41283d9
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -2920,16 -3017,18 +2923,18 @@@ a `js2-label-node' or the innermost enc
                                                         (ftype 'FUNCTION)
                                                         (form 
'FUNCTION_STATEMENT)
                                                         (name "")
-                                                        params body
+                                                        params rest-p
+                                                        body
                                                         lp rp)))
    "AST node for a function declaration.
 -The `params' field is a lisp list of nodes.  Each node is either a simple
 +The `params' field is a Lisp list of nodes.  Each node is either a simple
  `js2-name-node', or if it's a destructuring-assignment parameter, a
  `js2-array-node' or `js2-object-node'."
    ftype            ; FUNCTION, GETTER or SETTER
    form             ; FUNCTION_{STATEMENT|EXPRESSION|EXPRESSION_STATEMENT}
    name             ; function name (a `js2-name-node', or nil if anonymous)
 -  params           ; a lisp list of destructuring forms or simple name nodes
 +  params           ; a Lisp list of destructuring forms or simple name nodes
+   rest-p           ; if t, the last parameter is rest parameter
    body             ; a `js2-block-node' or expression node (1.8 only)
    lp               ; position of arg-list open-paren, or nil if omitted
    rp               ; position of arg-list close-paren, or nil if omitted
@@@ -3655,10 -3791,13 +3663,11 @@@ as opposed to required parens such as t
              (:constructor nil)
              (:constructor make-js2-array-comp-loop-node (&key (type js2-FOR)
                                                                (pos 
js2-ts-cursor)
 -                                                              len
 -                                                              iterator
 -                                                              object
 -                                                              in-pos
 +                                                              len iterator
 +                                                              object in-pos
                                                                foreach-p
                                                                each-pos
+                                                               forof-p
                                                                lp rp)))
    "AST subtree for each 'for (foo in bar)' loop in an array comprehension.")
  
@@@ -3670,11 -3809,11 +3679,13 @@@
    (js2-visit-ast (js2-array-comp-loop-node-object n) v))
  
  (defun js2-print-array-comp-loop (n i)
 -  (insert "for (")
 +  (insert "for ")
 +  (when (js2-array-comp-loop-node-foreach-p n) (insert "each "))
 +  (insert "(")
    (js2-print-ast (js2-array-comp-loop-node-iterator n) 0)
-   (insert " in ")
+   (if (js2-array-comp-loop-node-forof-p n)
+       (insert " of ")
+     (insert " in "))
    (js2-print-ast (js2-array-comp-loop-node-object n) 0)
    (insert ")"))
  
@@@ -6989,13 -7185,25 +7003,25 @@@ Returns nil and consumes nothing if MAT
      (js2-consume-token)
      t))
  
+ (defun js2-match-contextual-kwd (name)
+   "Consume and return t if next token is `js2-NAME', and its
+ string is NAME.  Returns nil and does nothing otherwise."
+   (if (or (/= (js2-peek-token) js2-NAME)
+           (not (string= js2-ts-string name)))
+       nil
+     (js2-consume-token)
+     (js2-record-face 'font-lock-keyword-face)
+     t))
+ 
 -(defsubst js2-valid-prop-name-token (tt)
 +(defun js2-valid-prop-name-token (tt)
    (or (= tt js2-NAME)
-       (and js2-allow-keywords-as-property-names
-            (plusp tt)
-            (aref js2-kwd-tokens tt))))
+       (when (and js2-allow-keywords-as-property-names
+                  (plusp tt)
+                  (aref js2-kwd-tokens tt))
+         (js2-save-name-token-data js2-token-beg (js2-token-name tt))
+         t)))
  
 -(defsubst js2-match-prop-name ()
 +(defun js2-match-prop-name ()
    "Consume token and return t if next token is a valid property name.
  It's valid if it's a js2-NAME, or `js2-allow-keywords-as-property-names'
  is non-nil and it's a keyword token."
@@@ -7273,22 -7481,54 +7299,54 @@@ NODE is either `js2-array-node', `js2-o
              (cond
               ;; destructuring param
               ((or (= tt js2-LB) (= tt js2-LC))
-               (setq param (js2-parse-primary-expr-lhs))
+               (when default-found
+                 (js2-report-error "msg.no.default.after.default.param"))
+               (setq param (js2-parse-destruct-primary-expr))
                (js2-define-destruct-symbols param
                                             js2-LP
 -                                           'js2-function-param-face)
 +                                           'js2-function-param)
                (push param params))
-              ;; simple name
+              ;; variable name
               (t
+               (when (and (>= js2-language-version 200)
+                          (js2-match-token js2-TRIPLEDOT)
+                          (not rest-param-at))
+                 ;; to report errors if there are more parameters
+                 (setq rest-param-at (length params)))
                (js2-must-match js2-NAME "msg.no.parm")
 -              (js2-record-face 'js2-function-param-face)
 +              (js2-record-face 'js2-function-param)
                (setq param (js2-create-name-node))
                (js2-define-symbol js2-LP js2-ts-string param)
+               ;; default parameter value
+               (when (or (and default-found
+                              (not rest-param-at)
+                              (js2-must-match js2-ASSIGN
+                                              
"msg.no.default.after.default.param"
+                                              (js2-node-pos param)
+                                              (js2-node-len param)))
+                         (and (>= js2-language-version 200)
+                              (js2-match-token js2-ASSIGN)))
+                 (let* ((pos (js2-node-pos param))
+                        (tt js2-current-token)
+                        (op-pos (- js2-token-beg pos))
+                        (left param)
+                        (right (js2-parse-assign-expr))
+                        (len (- (js2-node-end right) pos)))
+                   (setq param (make-js2-assign-node
+                                :type tt :pos pos :len len :op-pos op-pos
+                                :left left :right right)
+                         default-found t)
+                   (js2-node-add-children param left right)))
                (push param params)))
+             (when (and rest-param-at (> (length params) (1+ rest-param-at)))
+               (js2-report-error "msg.param.after.rest" nil
+                                 (js2-node-pos param) (js2-node-len param)))
              while
              (js2-match-token js2-COMMA))
-       (if (js2-must-match js2-RP "msg.no.paren.after.parms")
-           (setf (js2-function-node-rp fn-node) (- js2-token-beg pos)))
+       (when (js2-must-match js2-RP "msg.no.paren.after.parms")
+         (setf (js2-function-node-rp fn-node) (- js2-token-beg pos)))
+       (when rest-param-at
+         (setf (js2-function-node-rest-p fn-node) t))
        (dolist (p params)
          (js2-node-add-children fn-node p)
          (push p (js2-function-node-params fn-node))))))
@@@ -9133,9 -9433,12 +9195,9 @@@ array-literals, array comprehensions an
    (let ((pos js2-token-beg)
          (end js2-token-end)
          (after-lb-or-comma t)
 -        after-comma
 -        tt
 -        elems
 -        pn
 +        after-comma tt elems pn
          (continue t))
-     (unless js2-is-in-lhs
+     (unless js2-is-in-destructuring
          (js2-push-scope (make-js2-scope))) ; for array comp
      (while continue
        (setq tt (js2-peek-token))

commit 858b079d3ee5bf8ab7623b817f73cf958e684e02
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 12:33:25 2012 +0400

    Make some lines tighter

diff --git a/js2-mode.el b/js2-mode.el
index 8fd5502..a2887e5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2558,10 +2558,8 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                      object
                                                      in-pos
                                                      each-pos
-                                                     foreach-p
-                                                     forof-p
-                                                     lp
-                                                     rp)))
+                                                     foreach-p forof-p
+                                                     lp rp)))
   "AST node for a for..in loop."
   iterator  ; [var] foo in ...
   object    ; object over which we're iterating
@@ -3019,11 +3017,9 @@ a `js2-label-node' or the innermost enclosing loop.")
                                                        (ftype 'FUNCTION)
                                                        (form 
'FUNCTION_STATEMENT)
                                                        (name "")
-                                                       params
-                                                       rest-p
+                                                       params rest-p
                                                        body
-                                                       lp
-                                                       rp)))
+                                                       lp rp)))
   "AST node for a function declaration.
 The `params' field is a lisp list of nodes.  Each node is either a simple
 `js2-name-node', or if it's a destructuring-assignment parameter, a
@@ -3802,8 +3798,7 @@ as opposed to required parens such as those enclosing an 
if-conditional."
                                                               foreach-p
                                                               each-pos
                                                               forof-p
-                                                              lp
-                                                              rp)))
+                                                              lp rp)))
   "AST subtree for each 'for (foo in bar)' loop in an array comprehension.")
 
 (put 'cl-struct-js2-array-comp-loop-node 'js2-visitor 
'js2-visit-array-comp-loop)
@@ -7958,20 +7953,12 @@ Return value is a list (EXPR LP RP), with absolute 
paren positions."
   "Parser for for-statement.  Last matched token must be js2-FOR.
 Parses for, for-in, and for each-in statements."
   (let ((for-pos js2-token-beg)
-        pn
-        is-for-each
-        is-for-in-or-of
-        is-for-of
-        in-pos
-        each-pos
-        tmp-pos
+        pn is-for-each is-for-in-or-of is-for-of
+        in-pos each-pos tmp-pos
         init  ; Node init is also foo in 'foo in object'
         cond  ; Node cond is also object in 'foo in object'
         incr  ; 3rd section of for-loop initializer
-        body
-        tt
-        lp
-        rp)
+        body tt lp rp)
     (js2-consume-token)
     ;; See if this is a for each () instead of just a for ()
     (when (js2-match-token js2-NAME)
@@ -9557,15 +9544,7 @@ We should have just parsed the 'for' keyword before 
calling this function."
 Last token peeked should be the initial FOR."
   (let ((pos js2-token-beg)
         (pn (make-js2-array-comp-loop-node))
-        tt
-        iter
-        obj
-        foreach-p
-        forof-p
-        in-pos
-        each-pos
-        lp
-        rp)
+        tt iter obj foreach-p forof-p in-pos each-pos lp rp)
     (assert (= (js2-next-token) js2-FOR))  ; consumes token
     (js2-push-scope pn)
     (unwind-protect

commit d27c8afd4a3fd27fa1eea037f61b5c74bba8ddb1
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 12:13:48 2012 +0400

    Fix comment

diff --git a/js2-mode.el b/js2-mode.el
index 3d1ef5d..8fd5502 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3032,7 +3032,7 @@ The `params' field is a lisp list of nodes.  Each node is 
either a simple
   form             ; FUNCTION_{STATEMENT|EXPRESSION|EXPRESSION_STATEMENT}
   name             ; function name (a `js2-name-node', or nil if anonymous)
   params           ; a lisp list of destructuring forms or simple name nodes
-  rest-p           ; if t, the last
+  rest-p           ; if t, the last parameter is rest parameter
   body             ; a `js2-block-node' or expression node (1.8 only)
   lp               ; position of arg-list open-paren, or nil if omitted
   rp               ; position of arg-list close-paren, or nil if omitted

commit e45e9c8ee2c9d9b496acb3bc0ecac02381b4cc4d
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 11:42:41 2012 +0400

    Parse rest parameter
    
    Closes #51

diff --git a/js2-mode.el b/js2-mode.el
index 1a94fd4..3d1ef5d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -675,8 +675,9 @@ which doesn't seem particularly useful, but Rhino permits 
it."
 
 (defvar js2-COMMENT 160)
 (defvar js2-ENUM 161)  ; for "enum" reserved word
+(defvar js2-TRIPLEDOT 162) ; for rest parameter
 
-(defconst js2-num-tokens (1+ js2-ENUM))
+(defconst js2-num-tokens (1+ js2-TRIPLEDOT))
 
 (defconst js2-debug-print-trees nil)
 
@@ -1565,6 +1566,9 @@ the correct number of ARGS must be provided."
 (js2-msg "msg.no.default.after.default.param" ; added by js2-mode
          "parameter without default follows parameter with default")
 
+(js2-msg "msg.param.after.rest" ; added by js2-mode
+         "parameter after rest parameter")
+
 (js2-msg "msg.no.brace.body"
          "missing '{' before function body")
 
@@ -3016,6 +3020,7 @@ a `js2-label-node' or the innermost enclosing loop.")
                                                        (form 
'FUNCTION_STATEMENT)
                                                        (name "")
                                                        params
+                                                       rest-p
                                                        body
                                                        lp
                                                        rp)))
@@ -3027,6 +3032,7 @@ The `params' field is a lisp list of nodes.  Each node is 
either a simple
   form             ; FUNCTION_{STATEMENT|EXPRESSION|EXPRESSION_STATEMENT}
   name             ; function name (a `js2-name-node', or nil if anonymous)
   params           ; a lisp list of destructuring forms or simple name nodes
+  rest-p           ; if t, the last
   body             ; a `js2-block-node' or expression node (1.8 only)
   lp               ; position of arg-list open-paren, or nil if omitted
   rp               ; position of arg-list close-paren, or nil if omitted
@@ -3049,6 +3055,7 @@ The `params' field is a lisp list of nodes.  Each node is 
either a simple
         (getter (js2-node-get-prop n 'GETTER_SETTER))
         (name (js2-function-node-name n))
         (params (js2-function-node-params n))
+        (rest-p (js2-function-node-rest-p n))
         (body (js2-function-node-body n))
         (expr (eq (js2-function-node-form n) 'FUNCTION_EXPRESSION)))
     (unless getter
@@ -3061,9 +3068,11 @@ The `params' field is a lisp list of nodes.  Each node 
is either a simple
           for param in params
           for count from 1
           do
+          (when (and rest-p (= count len))
+            (insert "..."))
           (js2-print-ast param 0)
-          (if (< count len)
-              (insert ", ")))
+          (when (< count len)
+            (insert ", ")))
     (insert ") {")
     (unless expr
       (insert "\n"))
@@ -5828,7 +5837,9 @@ corresponding number.  Otherwise return -1."
              (throw 'return js2-COLON)))
           (?.
            (if (js2-match-char ?.)
-               (js2-ts-return js2-DOTDOT)
+               (if (js2-match-char ?.)
+                   (js2-ts-return js2-TRIPLEDOT)
+                 (js2-ts-return js2-DOTDOT))
              (if (js2-match-char ?\()
                  (js2-ts-return js2-DOTQUERY)
                (throw 'return js2-DOT))))
@@ -7469,7 +7480,7 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
 (defun js2-parse-function-params (fn-node pos)
   (if (js2-match-token js2-RP)
       (setf (js2-function-node-rp fn-node) (- js2-token-beg pos))
-    (let (params len param default-found)
+    (let (params len param default-found rest-param-at)
       (loop for tt = (js2-peek-token)
             do
             (cond
@@ -7484,12 +7495,18 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
               (push param params))
              ;; variable name
              (t
+              (when (and (>= js2-language-version 200)
+                         (js2-match-token js2-TRIPLEDOT)
+                         (not rest-param-at))
+                ;; to report errors if there are more parameters
+                (setq rest-param-at (length params)))
               (js2-must-match js2-NAME "msg.no.parm")
               (js2-record-face 'js2-function-param-face)
               (setq param (js2-create-name-node))
               (js2-define-symbol js2-LP js2-ts-string param)
               ;; default parameter value
               (when (or (and default-found
+                             (not rest-param-at)
                              (js2-must-match js2-ASSIGN
                                              
"msg.no.default.after.default.param"
                                              (js2-node-pos param)
@@ -7508,10 +7525,15 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
                         default-found t)
                   (js2-node-add-children param left right)))
               (push param params)))
+            (when (and rest-param-at (> (length params) (1+ rest-param-at)))
+              (js2-report-error "msg.param.after.rest" nil
+                                (js2-node-pos param) (js2-node-len param)))
             while
             (js2-match-token js2-COMMA))
-      (if (js2-must-match js2-RP "msg.no.paren.after.parms")
-          (setf (js2-function-node-rp fn-node) (- js2-token-beg pos)))
+      (when (js2-must-match js2-RP "msg.no.paren.after.parms")
+        (setf (js2-function-node-rp fn-node) (- js2-token-beg pos)))
+      (when rest-param-at
+        (setf (js2-function-node-rest-p fn-node) t))
       (dolist (p params)
         (js2-node-add-children fn-node p)
         (push p (js2-function-node-params fn-node))))))
diff --git a/tests/ast.el b/tests/ast.el
index b67960d..1611049 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -17,6 +17,7 @@
           (destructuring-bind (_ pos len) (first errors)
             (should (string= syntax-error (substring code-string
                                                      (1- pos) (+ pos len 
-1))))))
+      (should (= 0 (length (js2-ast-root-errors ast))))
       (ert-with-test-buffer (:name 'copy)
         (js2-print-tree ast)
         (skip-chars-backward " \t\n")
@@ -82,9 +83,9 @@ BIND defines bindings to apply them around the test."
   "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
 
 (js2-deftest-ast destruct-in-catch-clause
-  "try {\n} catch ({a, b}) {\n  return a + b;\n}")
+  "try {\n} catch ({a, b}) {\n  a + b;\n}")
 
-;;; Function arguments.
+;;; Function parameters.
 
 (js2-deftest-ast function-with-default-parameters
   "function foo(a = 1, b = a + 1) {\n}")
@@ -96,3 +97,17 @@ BIND defines bindings to apply them around the test."
 (js2-deftest-ast function-with-destruct-after-default
   "function foo(a = 1, {b, c}) {\n}"
   :syntax-error "{")
+
+(js2-deftest-ast function-with-rest-parameter
+  "function foo(a, b, ...rest) {\n}")
+
+(js2-deftest-ast function-with-param-after-rest-parameter
+  "function foo(a, ...b, rest) {\n}"
+  :syntax-error "rest")
+
+(js2-deftest-ast function-with-destruct-after-rest-parameter
+  "function foo(a, ...b, {}) {\n}"
+  :syntax-error "{}")
+
+(js2-deftest-ast function-with-rest-after-default-parameter
+  "function foo(a = 1, ...rest) {\n}")

commit cd50c7b7303886b71fc6fcca3526d896784e4bf6
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 10:16:14 2012 +0400

    Parse default parameters
    
    Closes #50

diff --git a/js2-mode.el b/js2-mode.el
index 215af34..1a94fd4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1562,6 +1562,9 @@ the correct number of ARGS must be provided."
 (js2-msg "msg.no.paren.after.parms"
          "missing ) after formal parameters")
 
+(js2-msg "msg.no.default.after.default.param" ; added by js2-mode
+         "parameter without default follows parameter with default")
+
 (js2-msg "msg.no.brace.body"
          "missing '{' before function body")
 
@@ -7466,23 +7469,44 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
 (defun js2-parse-function-params (fn-node pos)
   (if (js2-match-token js2-RP)
       (setf (js2-function-node-rp fn-node) (- js2-token-beg pos))
-    (let (params len param)
+    (let (params len param default-found)
       (loop for tt = (js2-peek-token)
             do
             (cond
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
+              (when default-found
+                (js2-report-error "msg.no.default.after.default.param"))
               (setq param (js2-parse-destruct-primary-expr))
               (js2-define-destruct-symbols param
                                            js2-LP
                                            'js2-function-param-face)
               (push param params))
-             ;; simple name
+             ;; variable name
              (t
               (js2-must-match js2-NAME "msg.no.parm")
               (js2-record-face 'js2-function-param-face)
               (setq param (js2-create-name-node))
               (js2-define-symbol js2-LP js2-ts-string param)
+              ;; default parameter value
+              (when (or (and default-found
+                             (js2-must-match js2-ASSIGN
+                                             
"msg.no.default.after.default.param"
+                                             (js2-node-pos param)
+                                             (js2-node-len param)))
+                        (and (>= js2-language-version 200)
+                             (js2-match-token js2-ASSIGN)))
+                (let* ((pos (js2-node-pos param))
+                       (tt js2-current-token)
+                       (op-pos (- js2-token-beg pos))
+                       (left param)
+                       (right (js2-parse-assign-expr))
+                       (len (- (js2-node-end right) pos)))
+                  (setq param (make-js2-assign-node
+                               :type tt :pos pos :len len :op-pos op-pos
+                               :left left :right right)
+                        default-found t)
+                  (js2-node-add-children param left right)))
               (push param params)))
             while
             (js2-match-token js2-COMMA))
diff --git a/tests/ast.el b/tests/ast.el
index 7644aea..b67960d 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -9,21 +9,29 @@
     (should (null js2-mode-buffer-dirty-p))
     js2-mode-ast))
 
-(defun js2-test-ast-string (code-string)
+(defun js2-test-ast-string (code-string &key syntax-error)
   (let ((ast (js2-test-string-to-ast code-string)))
-    (ert-with-test-buffer (:name 'copy)
-      (js2-print-tree ast)
-      (skip-chars-backward " \t\n")
-      (should (string= code-string (buffer-substring-no-properties
-                                    (point-min) (point)))))))
-
-(defmacro js2-deftest-ast (name code-string &optional bindings)
-  "Parse CODE-STRING, print it out with `js2-print-tree', and
-assert the result to be equal to the original string.
-When BINDINGS are specified, apply them around the test."
+    (if syntax-error
+        (let ((errors (js2-ast-root-errors ast)))
+          (should (= 1 (length errors)))
+          (destructuring-bind (_ pos len) (first errors)
+            (should (string= syntax-error (substring code-string
+                                                     (1- pos) (+ pos len 
-1))))))
+      (ert-with-test-buffer (:name 'copy)
+        (js2-print-tree ast)
+        (skip-chars-backward " \t\n")
+        (should (string= code-string (buffer-substring-no-properties
+                                      (point-min) (point))))))))
+
+(defmacro* js2-deftest-ast (name code-string &key bind syntax-error)
+  "Parse CODE-STRING.  If SYNTAX-ERROR is nil, print syntax tree
+with `js2-print-tree' and assert the result to be equal to the
+original string.  If SYNTAX-ERROR is passed, expect syntax error
+highlighting substring equal to SYNTAX-ERROR value.
+BIND defines bindings to apply them around the test."
   `(ert-deftest ,name ()
-     (let ,(append bindings '((js2-basic-offset 2)))
-       (js2-test-ast-string ,code-string))))
+     (let ,(append bind '((js2-basic-offset 2)))
+       (js2-test-ast-string ,code-string :syntax-error ,syntax-error))))
 
 (put 'js2-deftest-ast 'lisp-indent-function 'defun)
 
@@ -34,19 +42,19 @@ When BINDINGS are specified, apply them around the test."
 
 (js2-deftest-ast parse-property-access-when-keyword
   "A.in = 3;"
-  ((js2-allow-keywords-as-property-names t)))
+  :bind ((js2-allow-keywords-as-property-names t)))
 
 (js2-deftest-ast parse-property-access-when-keyword-no-xml
   "A.in = 3;"
-  ((js2-allow-keywords-as-property-names t)
-   (js2-compiler-xml-available nil)))
+  :bind ((js2-allow-keywords-as-property-names t)
+         (js2-compiler-xml-available nil)))
 
 (js2-deftest-ast parse-array-literal-when-not-keyword
   "a = {b: 1};")
 
 (js2-deftest-ast parse-array-literal-when-keyword
   "a = {in: 1};"
-  ((js2-allow-keywords-as-property-names t)))
+  :bind ((js2-allow-keywords-as-property-names t)))
 
 ;;; 'of' contextual keyword.
 
@@ -75,3 +83,16 @@ When BINDINGS are specified, apply them around the test."
 
 (js2-deftest-ast destruct-in-catch-clause
   "try {\n} catch ({a, b}) {\n  return a + b;\n}")
+
+;;; Function arguments.
+
+(js2-deftest-ast function-with-default-parameters
+  "function foo(a = 1, b = a + 1) {\n}")
+
+(js2-deftest-ast function-with-no-default-after-default
+  "function foo(a = 1, b) {\n}"
+  :syntax-error "b")
+
+(js2-deftest-ast function-with-destruct-after-default
+  "function foo(a = 1, {b, c}) {\n}"
+  :syntax-error "{")

commit e67ed6620ca2944d75e0ec66219e663171877d1b
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 08:19:43 2012 +0400

    Simplify `js2-test-ast-string'

diff --git a/tests/ast.el b/tests/ast.el
index cbb96f4..7644aea 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -4,20 +4,18 @@
 
 (defun js2-test-string-to-ast (s)
   (ert-with-test-buffer (:name 'origin)
-      (insert s)
-      (js2-mode)
-      (should (null js2-mode-buffer-dirty-p))
-      js2-mode-ast))
+    (insert s)
+    (js2-mode)
+    (should (null js2-mode-buffer-dirty-p))
+    js2-mode-ast))
 
 (defun js2-test-ast-string (code-string)
   (let ((ast (js2-test-string-to-ast code-string)))
     (ert-with-test-buffer (:name 'copy)
       (js2-print-tree ast)
       (skip-chars-backward " \t\n")
-      (delete-region (point) (point-max))
-      (should (string= code-string
-                       (buffer-substring-no-properties
-                        (point-min) (point-max)))))))
+      (should (string= code-string (buffer-substring-no-properties
+                                    (point-min) (point)))))))
 
 (defmacro js2-deftest-ast (name code-string &optional bindings)
   "Parse CODE-STRING, print it out with `js2-print-tree', and

commit 81eaac3d482d20e154b5e76d714107a176c40018
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 08:10:54 2012 +0400

    Set js2-basic-offset in tests explicitly

diff --git a/tests/ast.el b/tests/ast.el
index ed354cc..cbb96f4 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -24,7 +24,7 @@
 assert the result to be equal to the original string.
 When BINDINGS are specified, apply them around the test."
   `(ert-deftest ,name ()
-     (let ,bindings
+     (let ,(append bindings '((js2-basic-offset 2)))
        (js2-test-ast-string ,code-string))))
 
 (put 'js2-deftest-ast 'lisp-indent-function 'defun)

commit 30b33129c0fd84fd689d6df70d1062f5295d93c7
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 08:00:30 2012 +0400

    Print space after colon in prop nodes

diff --git a/js2-mode.el b/js2-mode.el
index d7bed5e..215af34 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3574,7 +3574,7 @@ The `right' field is a `js2-node' representing the 
initializer value.")
 (defun js2-print-object-prop-node (n i)
   (insert (js2-make-pad i))
   (js2-print-ast (js2-object-prop-node-left n) 0)
-  (insert ":")
+  (insert ": ")
   (js2-print-ast (js2-object-prop-node-right n) 0))
 
 (defstruct (js2-getter-setter-node
diff --git a/tests/ast.el b/tests/ast.el
index 16237eb..ed354cc 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -44,10 +44,10 @@ When BINDINGS are specified, apply them around the test."
    (js2-compiler-xml-available nil)))
 
 (js2-deftest-ast parse-array-literal-when-not-keyword
-  "a = {b:1};")
+  "a = {b: 1};")
 
 (js2-deftest-ast parse-array-literal-when-keyword
-  "a = {in:1};"
+  "a = {in: 1};"
   ((js2-allow-keywords-as-property-names t)))
 
 ;;; 'of' contextual keyword.
@@ -67,10 +67,10 @@ When BINDINGS are specified, apply them around the test."
 ;;; Destructuring binding.
 
 (js2-deftest-ast destruct-in-declaration
-  "var {a, b} = {a:1, b:2};")
+  "var {a, b} = {a: 1, b: 2};")
 
 (js2-deftest-ast destruct-in-arguments
-  "function f({a:aa, b:bb}) {\n}")
+  "function f({a: aa, b: bb}) {\n}")
 
 (js2-deftest-ast destruct-in-array-comp-loop
   "[a + b for ([a, b] in [[0, 1], [1, 2]])];")

commit 3dfcca0eda08ea6be763876de4b20714e8cafcec
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 07:59:02 2012 +0400

    Fix catch param with destructuring binding

diff --git a/js2-mode.el b/js2-mode.el
index bbb0949..d7bed5e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -8054,9 +8054,8 @@ Parses for, for-in, and for each-in statements."
            ;; destructuring pattern
            ;;     catch ({ message, file }) { ... }
            ((or (= tt js2-LB) (= tt js2-LC))
-            (setq param
-                  (js2-define-destruct-symbols 
(js2-parse-destruct-primary-expr)
-                                               js2-LET nil)))
+            (setq param (js2-parse-destruct-primary-expr))
+            (js2-define-destruct-symbols param js2-LET nil))
            ;; simple name
            (t
             (js2-must-match js2-NAME "msg.bad.catchcond")
diff --git a/tests/ast.el b/tests/ast.el
index 0c9a823..16237eb 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -75,5 +75,5 @@ When BINDINGS are specified, apply them around the test."
 (js2-deftest-ast destruct-in-array-comp-loop
   "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
 
-;; (js2-deftest-ast destruct-in-catch-clause
-;;   "try {\n} catch ({a, b}) {return a + b;}")
+(js2-deftest-ast destruct-in-catch-clause
+  "try {\n} catch ({a, b}) {\n  return a + b;\n}")

commit 646087a498bb89037ab2d09efab9fbc3c5c0d326
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 17 07:54:39 2012 +0400

    Rename js2-is-in-lhs -> js2-is-in-destructuring (like in Rhino)
    
    * Edit comments.
    * Add some tests.

diff --git a/js2-mode.el b/js2-mode.el
index 8641752..bbb0949 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -817,16 +817,8 @@ Will only be used when we finish implementing the 
interpreter.")
 (js2-deflocal js2-recorded-identifiers nil
   "Tracks identifiers found during parsing.")
 
-(defmacro js2-in-lhs (body)
-  `(let ((js2-is-in-lhs t))
-     ,body))
-
-(defmacro js2-in-rhs (body)
-  `(let ((js2-is-in-lhs nil))
-     ,body))
-
-(js2-deflocal js2-is-in-lhs nil
-  "True while parsing lhs statement")
+(js2-deflocal js2-is-in-destructuring nil
+  "True while parsing destructuring expression.")
 
 (defcustom js2-global-externs nil
   "A list of any extern names you'd like to consider always declared.
@@ -7480,7 +7472,7 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
             (cond
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
-              (setq param (js2-parse-primary-expr-lhs))
+              (setq param (js2-parse-destruct-primary-expr))
               (js2-define-destruct-symbols param
                                            js2-LP
                                            'js2-function-param-face)
@@ -8063,7 +8055,7 @@ Parses for, for-in, and for each-in statements."
            ;;     catch ({ message, file }) { ... }
            ((or (= tt js2-LB) (= tt js2-LC))
             (setq param
-                  (js2-define-destruct-symbols (js2-parse-primary-expr-lhs)
+                  (js2-define-destruct-symbols 
(js2-parse-destruct-primary-expr)
                                                js2-LET nil)))
            ;; simple name
            (t
@@ -8506,7 +8498,7 @@ Returns the parsed `js2-var-decl-node' expression node."
             init nil)
       (if (or (= tt js2-LB) (= tt js2-LC))
           ;; Destructuring assignment, e.g., var [a, b] = ...
-          (setq destructuring (js2-parse-primary-expr-lhs)
+          (setq destructuring (js2-parse-destruct-primary-expr)
                 end (js2-node-end destructuring))
         ;; Simple variable name
         (when (js2-must-match js2-NAME "msg.bad.var")
@@ -9287,8 +9279,8 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
                                           :rb (js2-relpos rb pos)))
       (js2-node-add-children pn namespace expr))))
 
-(defun js2-parse-primary-expr-lhs ()
-  (let ((js2-is-in-lhs t))
+(defun js2-parse-destruct-primary-expr ()
+  (let ((js2-is-in-destructuring t))
     (js2-parse-primary-expr)))
 
 (defun js2-parse-primary-expr ()
@@ -9414,7 +9406,7 @@ array-literals, array comprehensions and regular 
expressions."
         elems
         pn
         (continue t))
-    (unless js2-is-in-lhs
+    (unless js2-is-in-destructuring
         (js2-push-scope (make-js2-scope))) ; for array comp
     (while continue
       (setq tt (js2-peek-token))
@@ -9438,16 +9430,16 @@ array-literals, array comprehensions and regular 
expressions."
                                       :len (- js2-ts-cursor pos)
                                       :elems (nreverse elems)))
         (apply #'js2-node-add-children pn (js2-array-node-elems pn))
-        (when (and after-comma (not js2-is-in-lhs))
+        (when (and after-comma (not js2-is-in-destructuring))
           (js2-parse-warn-trailing-comma "msg.array.trailing.comma"
                                          pos elems after-comma)))
        ;; destructuring binding
-       (js2-is-in-lhs
+       (js2-is-in-destructuring
         (push (if (or (= tt js2-LC)
                       (= tt js2-LB)
                       (= tt js2-NAME))
                   ;; [a, b, c] | {a, b, c} | {a:x, b:y, c:z} | a
-                  (js2-parse-primary-expr-lhs)
+                  (js2-parse-destruct-primary-expr)
                 ;; invalid pattern
                 (js2-consume-token)
                 (js2-report-error "msg.bad.var")
@@ -9471,7 +9463,7 @@ array-literals, array comprehensions and regular 
expressions."
         (push (js2-parse-assign-expr) elems)
         (setq after-lb-or-comma nil
               after-comma nil))))
-    (unless js2-is-in-lhs
+    (unless js2-is-in-destructuring
       (js2-pop-scope))
     pn))
 
@@ -9546,8 +9538,7 @@ Last token peeked should be the initial FOR."
           (cond
            ((or (= tt js2-LB)
                 (= tt js2-LC))
-            ;; handle destructuring assignment
-            (setq iter (js2-parse-primary-expr-lhs))
+            (setq iter (js2-parse-destruct-primary-expr))
             (js2-define-destruct-symbols iter js2-LET
                                          'font-lock-variable-name-face t))
            ((js2-match-token js2-NAME)
@@ -9559,9 +9550,9 @@ Last token peeked should be the initial FOR."
           (if (js2-name-node-p iter)
               (js2-define-symbol js2-LET (js2-name-node-name iter) pn t))
           (if (or (js2-match-token js2-IN)
-              (and (>= js2-language-version 200)
-                   (js2-match-contextual-kwd "of")
-                   (setq forof-p t)))
+                  (and (>= js2-language-version 200)
+                       (js2-match-contextual-kwd "of")
+                       (setq forof-p t)))
               (setq in-pos (- js2-token-beg pos))
             (js2-report-error "msg.in.after.for.name"))
           (setq obj (js2-parse-expr))
@@ -9627,7 +9618,7 @@ Last token peeked should be the initial FOR."
 
 (defun js2-parse-named-prop (tt)
   "Parse a name, string, or getter/setter object property.
-When `js2-is-in-lhs' is t, forms like {a, b, c} will be permitted."
+When `js2-is-in-destructuring' is t, forms like {a, b, c} will be permitted."
   (js2-consume-token)
   (let ((string-prop (and (= tt js2-STRING)
                           (make-js2-string-node)))
@@ -9647,12 +9638,14 @@ When `js2-is-in-lhs' is t, forms like {a, b, c} will be 
permitted."
       (js2-record-face 'font-lock-function-name-face)      ; for peeked name
       (setq name (js2-create-name-node)) ; discard get/set & use peeked name
       (js2-parse-getter-setter-prop ppos name (string= prop "get")))
-     ;; abbreviated destructuring bind e.g., {a, b} = c;
-     ;; XXX: To be honest, the value of `js2-is-in-lhs' becomes t only when
-     ;; patterns are appeared in variable declaration, function parameters, 
and catch-clause.
-     ;; We have to set t to `js2-is-in-lhs' when the current expressions are 
part of any
-     ;; assignment but it's difficult because it requires looking ahead of 
expression.
-     ((and js2-is-in-lhs
+     ;; Abbreviated destructuring binding, e.g. {a, b} = c;
+     ;; XXX: To be honest, the value of `js2-is-in-destructuring' becomes t 
only
+     ;; when patterns are used in variable declarations, function parameters,
+     ;; catch-clause, and iterators.
+     ;; We have to set `js2-is-in-destructuring' to t when the current
+     ;; expressions are on the left side of any assignment, but it's difficult
+     ;; because it requires looking ahead of expression.
+     ((and js2-is-in-destructuring
            (= tt js2-NAME)
            (let ((ctk (js2-peek-token)))
              (or (= ctk js2-COMMA)
diff --git a/tests/ast.el b/tests/ast.el
index cea9b8e..0c9a823 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -50,11 +50,6 @@ When BINDINGS are specified, apply them around the test."
   "a = {in:1};"
   ((js2-allow-keywords-as-property-names t)))
 
-;;; Misc.
-
-(js2-deftest-ast parse-array-comp-loop
-  "[a for (a in [])];")
-
 ;;; 'of' contextual keyword.
 
 (js2-deftest-ast parse-array-comp-loop-with-of
@@ -68,3 +63,17 @@ When BINDINGS are specified, apply them around the test."
 
 (js2-deftest-ast of-can-be-function-name
   "function of() {\n}")
+
+;;; Destructuring binding.
+
+(js2-deftest-ast destruct-in-declaration
+  "var {a, b} = {a:1, b:2};")
+
+(js2-deftest-ast destruct-in-arguments
+  "function f({a:aa, b:bb}) {\n}")
+
+(js2-deftest-ast destruct-in-array-comp-loop
+  "[a + b for ([a, b] in [[0, 1], [1, 2]])];")
+
+;; (js2-deftest-ast destruct-in-catch-clause
+;;   "try {\n} catch ({a, b}) {return a + b;}")

commit 5d49f01e2334ac7fcd2ca832a6eaa428b460018d
Author: Dmitry Gutov <address@hidden>
Date:   Fri Jun 15 22:45:12 2012 +0400

    Add test Makefile target

diff --git a/Makefile b/Makefile
index 77e9bba..3ff3d8c 100644
--- a/Makefile
+++ b/Makefile
@@ -18,3 +18,6 @@ clean:
 # custom build (require loads)
 js2-imenu-extras.elc: js2-mode.elc
        emacs $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el
+
+test:
+       emacs $(BATCHFLAGS) -l js2-mode.el -l tests/ast.el -f 
ert-run-tests-batch

commit be9054d5b87b0d702a43a459c804cd38020924bd
Author: Dmitry Gutov <address@hidden>
Date:   Thu Jun 14 17:03:06 2012 +0400

    Make 'of' contextual keyword
    
    Refs #53

diff --git a/js2-mode.el b/js2-mode.el
index 91253fc..8641752 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -675,9 +675,8 @@ which doesn't seem particularly useful, but Rhino permits 
it."
 
 (defvar js2-COMMENT 160)
 (defvar js2-ENUM 161)  ; for "enum" reserved word
-(defvar js2-OF 162)    ; for "for of" iterators
 
-(defconst js2-num-tokens (1+ js2-OF))
+(defconst js2-num-tokens (1+ js2-ENUM))
 
 (defconst js2-debug-print-trees nil)
 
@@ -5412,7 +5411,7 @@ into temp buffers."
     debugger default delete do
     else enum
     false finally for function
-    if in of instanceof import
+    if in instanceof import
     let
     new null
     return
@@ -5432,7 +5431,7 @@ into temp buffers."
                js2-DEBUGGER js2-DEFAULT js2-DELPROP js2-DO
                js2-ELSE
                js2-FALSE js2-FINALLY js2-FOR js2-FUNCTION
-               js2-IF js2-IN js2-OF js2-INSTANCEOF js2-IMPORT
+               js2-IF js2-IN js2-INSTANCEOF js2-IMPORT
                js2-LET
                js2-NEW js2-NULL
                js2-RETURN
@@ -7185,6 +7184,16 @@ Returns nil and consumes nothing if MATCH is not the 
next token."
     (js2-consume-token)
     t))
 
+(defun js2-match-contextual-kwd (name)
+  "Consume and return t if next token is `js2-NAME', and its
+string is NAME.  Returns nil and does nothing otherwise."
+  (if (or (/= (js2-peek-token) js2-NAME)
+          (not (string= js2-ts-string name)))
+      nil
+    (js2-consume-token)
+    (js2-record-face 'font-lock-keyword-face)
+    t))
+
 (defsubst js2-valid-prop-name-token (tt)
   (or (= tt js2-NAME)
       (when (and js2-allow-keywords-as-property-names
@@ -7952,7 +7961,7 @@ Parses for, for-in, and for each-in statements."
             (setq init (js2-parse-expr)))))
       (if (or (js2-match-token js2-IN)
               (and (>= js2-language-version 200)
-                   (js2-match-token js2-OF)
+                   (js2-match-contextual-kwd "of")
                    (setq is-for-of t)))
           (setq is-for-in-or-of t
                 in-pos (- js2-token-beg for-pos)
@@ -9551,7 +9560,7 @@ Last token peeked should be the initial FOR."
               (js2-define-symbol js2-LET (js2-name-node-name iter) pn t))
           (if (or (js2-match-token js2-IN)
               (and (>= js2-language-version 200)
-                   (js2-match-token js2-OF)
+                   (js2-match-contextual-kwd "of")
                    (setq forof-p t)))
               (setq in-pos (- js2-token-beg pos))
             (js2-report-error "msg.in.after.for.name"))
diff --git a/tests/ast.el b/tests/ast.el
index 4eb356e..cea9b8e 100644
--- a/tests/ast.el
+++ b/tests/ast.el
@@ -50,7 +50,21 @@ When BINDINGS are specified, apply them around the test."
   "a = {in:1};"
   ((js2-allow-keywords-as-property-names t)))
 
-;;; Other tests.
+;;; Misc.
 
 (js2-deftest-ast parse-array-comp-loop
   "[a for (a in [])];")
+
+;;; 'of' contextual keyword.
+
+(js2-deftest-ast parse-array-comp-loop-with-of
+  "[a for (a of [])];")
+
+(js2-deftest-ast parse-for-of
+  "for (var a of []) {\n}")
+
+(js2-deftest-ast of-can-be-var-name
+  "var of = 3;")
+
+(js2-deftest-ast of-can-be-function-name
+  "function of() {\n}")

commit d75365c1f9e423a7312c8997bc2aba613cdd58df
Author: Dmitry Gutov <address@hidden>
Date:   Thu Jun 14 15:43:49 2012 +0400

    Fix parsing of keyword property names
    
    Closes #54
    
    Also prohibit keyword identifiers in array comp loops

diff --git a/js2-mode.el b/js2-mode.el
index 7c5bbe4..91253fc 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -5204,8 +5204,9 @@ nor always false."
           do
           (unless (or (memq sym '(js2-EOF_CHAR js2-ERROR))
                       (not (boundp sym)))
-            (aset names (symbol-value sym)         ; code, e.g. 152
-                  (substring (symbol-name sym) 4)) ; name, e.g. "LET"
+            (aset names (symbol-value sym)           ; code, e.g. 152
+                  (downcase
+                   (substring (symbol-name sym) 4))) ; name, e.g. "let"
             (push sym js2-tokens)))
     names)
   "Vector mapping int values to token string names, sans `js2-' prefix.")
@@ -5231,7 +5232,7 @@ Signals an error if it's not a recognized token."
 (defconst js2-token-codes
   (let ((table (make-hash-table :test 'eq :size 256)))
     (loop for name across js2-token-names
-          for sym = (intern (concat "js2-" name))
+          for sym = (intern (concat "js2-" (upcase name)))
           do
           (puthash sym (symbol-value sym) table))
     ;; clean up a few that are "wrong" in Rhino's token codes
@@ -7186,9 +7187,11 @@ Returns nil and consumes nothing if MATCH is not the 
next token."
 
 (defsubst js2-valid-prop-name-token (tt)
   (or (= tt js2-NAME)
-      (and js2-allow-keywords-as-property-names
-           (plusp tt)
-           (aref js2-kwd-tokens tt))))
+      (when (and js2-allow-keywords-as-property-names
+                 (plusp tt)
+                 (aref js2-kwd-tokens tt))
+        (js2-save-name-token-data js2-token-beg (js2-token-name tt))
+        t)))
 
 (defsubst js2-match-prop-name ()
   "Consume token and return t if next token is a valid property name.
@@ -9538,8 +9541,7 @@ Last token peeked should be the initial FOR."
             (setq iter (js2-parse-primary-expr-lhs))
             (js2-define-destruct-symbols iter js2-LET
                                          'font-lock-variable-name-face t))
-           ((js2-valid-prop-name-token tt)
-            (js2-consume-token)
+           ((js2-match-token js2-NAME)
             (setq iter (js2-create-name-node)))
            (t
             (js2-report-error "msg.bad.var")))
diff --git a/tests/ast.el b/tests/ast.el
new file mode 100644
index 0000000..4eb356e
--- /dev/null
+++ b/tests/ast.el
@@ -0,0 +1,56 @@
+(require 'ert)
+(require 'ert-x)
+(require 'js2-mode)
+
+(defun js2-test-string-to-ast (s)
+  (ert-with-test-buffer (:name 'origin)
+      (insert s)
+      (js2-mode)
+      (should (null js2-mode-buffer-dirty-p))
+      js2-mode-ast))
+
+(defun js2-test-ast-string (code-string)
+  (let ((ast (js2-test-string-to-ast code-string)))
+    (ert-with-test-buffer (:name 'copy)
+      (js2-print-tree ast)
+      (skip-chars-backward " \t\n")
+      (delete-region (point) (point-max))
+      (should (string= code-string
+                       (buffer-substring-no-properties
+                        (point-min) (point-max)))))))
+
+(defmacro js2-deftest-ast (name code-string &optional bindings)
+  "Parse CODE-STRING, print it out with `js2-print-tree', and
+assert the result to be equal to the original string.
+When BINDINGS are specified, apply them around the test."
+  `(ert-deftest ,name ()
+     (let ,bindings
+       (js2-test-ast-string ,code-string))))
+
+(put 'js2-deftest-ast 'lisp-indent-function 'defun)
+
+;;; Callers of `js2-valid-prop-name-token'.
+
+(js2-deftest-ast parse-property-access-when-not-keyword
+  "A.foo = 3;")
+
+(js2-deftest-ast parse-property-access-when-keyword
+  "A.in = 3;"
+  ((js2-allow-keywords-as-property-names t)))
+
+(js2-deftest-ast parse-property-access-when-keyword-no-xml
+  "A.in = 3;"
+  ((js2-allow-keywords-as-property-names t)
+   (js2-compiler-xml-available nil)))
+
+(js2-deftest-ast parse-array-literal-when-not-keyword
+  "a = {b:1};")
+
+(js2-deftest-ast parse-array-literal-when-keyword
+  "a = {in:1};"
+  ((js2-allow-keywords-as-property-names t)))
+
+;;; Other tests.
+
+(js2-deftest-ast parse-array-comp-loop
+  "[a for (a in [])];")

commit 70b6756438d0ae0b14b015a78dc5aa30eab0c363
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 13 08:37:45 2012 +0400

    Support for..of in loops and array comprehensions
    
    Refs #53

diff --git a/js2-mode.el b/js2-mode.el
index 910279d..7c5bbe4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -382,12 +382,12 @@ Useful for viewing Mozilla JavaScript source code."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-language-version 180
+(defcustom js2-language-version 200
   "Configures what JavaScript language version to recognize.
-Currently versions 150, 160, 170 and 180 are supported, corresponding
-to JavaScript 1.5, 1.6, 1.7 and 1.8, respectively.  In a nutshell,
-1.6 adds E4X support, 1.7 adds let, yield, and Array comprehensions,
-and 1.8 adds function closures."
+Currently versions 150, 160, 170, 180 and 200 are supported,
+corresponding to JavaScript 1.5, 1.6, 1.7, 1.8 and 2.0 (Harmony),
+respectively.  In a nutshell, 1.6 adds E4X support, 1.7 adds let,
+yield, and Array comprehensions, and 1.8 adds function closures."
   :type 'integer
   :group 'js2-mode)
 
@@ -675,8 +675,9 @@ which doesn't seem particularly useful, but Rhino permits 
it."
 
 (defvar js2-COMMENT 160)
 (defvar js2-ENUM 161)  ; for "enum" reserved word
+(defvar js2-OF 162)    ; for "for of" iterators
 
-(defconst js2-num-tokens (1+ js2-ENUM))
+(defconst js2-num-tokens (1+ js2-OF))
 
 (defconst js2-debug-print-trees nil)
 
@@ -1634,7 +1635,7 @@ the correct number of ARGS must be provided."
          "missing ; after for-loop condition")
 
 (js2-msg "msg.in.after.for.name"
-         "missing in after for")
+         "missing in or of after for")
 
 (js2-msg "msg.no.paren.for.ctrl"
          "missing ) after for-loop control")
@@ -2560,6 +2561,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                      in-pos
                                                      each-pos
                                                      foreach-p
+                                                     forof-p
                                                      lp
                                                      rp)))
   "AST node for a for..in loop."
@@ -2567,7 +2569,8 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
   object    ; object over which we're iterating
   in-pos    ; buffer position of 'in' keyword
   each-pos  ; buffer position of 'each' keyword, if foreach-p
-  foreach-p) ; t if it's a for-each loop
+  foreach-p ; t if it's a for-each loop
+  forof-p)  ; t if it's a for-of loop
 
 (put 'cl-struct-js2-for-in-node 'js2-visitor 'js2-visit-for-in-node)
 (put 'cl-struct-js2-for-in-node 'js2-printer 'js2-print-for-in-node)
@@ -2579,13 +2582,16 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
 
 (defun js2-print-for-in-node (n i)
   (let ((pad (js2-make-pad i))
-        (foreach (js2-for-in-node-foreach-p n)))
+        (foreach (js2-for-in-node-foreach-p n))
+        (forof (js2-for-in-node-forof-p n)))
     (insert pad "for ")
     (if foreach
         (insert "each "))
     (insert "(")
     (js2-print-ast (js2-for-in-node-iterator n) 0)
-    (insert " in ")
+    (if forof
+        (insert " of ")
+      (insert " in "))
     (js2-print-ast (js2-for-in-node-object n) 0)
     (insert ") {\n")
     (js2-print-body (js2-for-in-node-body n) (1+ i))
@@ -3777,8 +3783,9 @@ as opposed to required parens such as those enclosing an 
if-conditional."
       (js2-print-ast l 0))
     (when filter
       (insert " if (")
-      (js2-print-ast filter 0))
-    (insert ")]")))
+      (js2-print-ast filter 0)
+      (insert ")"))
+    (insert "]")))
 
 (defstruct (js2-array-comp-loop-node
             (:include js2-for-in-node)
@@ -3791,6 +3798,7 @@ as opposed to required parens such as those enclosing an 
if-conditional."
                                                               in-pos
                                                               foreach-p
                                                               each-pos
+                                                              forof-p
                                                               lp
                                                               rp)))
   "AST subtree for each 'for (foo in bar)' loop in an array comprehension.")
@@ -3805,7 +3813,9 @@ as opposed to required parens such as those enclosing an 
if-conditional."
 (defun js2-print-array-comp-loop (n i)
   (insert "for (")
   (js2-print-ast (js2-array-comp-loop-node-iterator n) 0)
-  (insert " in ")
+  (if (js2-array-comp-loop-node-forof-p n)
+      (insert " of ")
+    (insert " in "))
   (js2-print-ast (js2-array-comp-loop-node-object n) 0)
   (insert ")"))
 
@@ -5401,7 +5411,7 @@ into temp buffers."
     debugger default delete do
     else enum
     false finally for function
-    if in instanceof import
+    if in of instanceof import
     let
     new null
     return
@@ -5421,7 +5431,7 @@ into temp buffers."
                js2-DEBUGGER js2-DEFAULT js2-DELPROP js2-DO
                js2-ELSE
                js2-FALSE js2-FINALLY js2-FOR js2-FUNCTION
-               js2-IF js2-IN js2-INSTANCEOF js2-IMPORT
+               js2-IF js2-IN js2-OF js2-INSTANCEOF js2-IMPORT
                js2-LET
                js2-NEW js2-NULL
                js2-RETURN
@@ -7900,7 +7910,8 @@ Parses for, for-in, and for each-in statements."
   (let ((for-pos js2-token-beg)
         pn
         is-for-each
-        is-for-in
+        is-for-in-or-of
+        is-for-of
         in-pos
         each-pos
         tmp-pos
@@ -7936,8 +7947,11 @@ Parses for, for-in, and for each-in statements."
             (setq init (js2-parse-variables tt js2-token-beg)))
            (t
             (setq init (js2-parse-expr)))))
-      (if (js2-match-token js2-IN)
-          (setq is-for-in t
+      (if (or (js2-match-token js2-IN)
+              (and (>= js2-language-version 200)
+                   (js2-match-token js2-OF)
+                   (setq is-for-of t)))
+          (setq is-for-in-or-of t
                 in-pos (- js2-token-beg for-pos)
                 ;; scope of iteration target object is not the scope we've 
created above.
                 ;; stash current scope temporary.
@@ -7955,7 +7969,7 @@ Parses for, for-in, and for each-in statements."
                      (js2-parse-expr))))
       (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
           (setq rp (- js2-token-beg for-pos)))
-      (if (not is-for-in)
+      (if (not is-for-in-or-of)
           (setq pn (make-js2-for-node :init init
                                       :condition cond
                                       :update incr
@@ -7974,6 +7988,7 @@ Parses for, for-in, and for each-in statements."
                                        :in-pos in-pos
                                        :foreach-p is-for-each
                                        :each-pos each-pos
+                                       :forof-p is-for-of
                                        :lp lp
                                        :rp rp)))
       (unwind-protect
@@ -9489,7 +9504,7 @@ We should have just parsed the 'for' keyword before 
calling this function."
     result))
 
 (defun js2-parse-array-comp-loop ()
-  "Parse a 'for [each] (foo in bar)' expression in an Array comprehension.
+  "Parse a 'for [each] (foo [in|of] bar)' expression in an Array comprehension.
 Last token peeked should be the initial FOR."
   (let ((pos js2-token-beg)
         (pn (make-js2-array-comp-loop-node))
@@ -9497,6 +9512,7 @@ Last token peeked should be the initial FOR."
         iter
         obj
         foreach-p
+        forof-p
         in-pos
         each-pos
         lp
@@ -9531,8 +9547,12 @@ Last token peeked should be the initial FOR."
           ;; be restricted to the array comprehension
           (if (js2-name-node-p iter)
               (js2-define-symbol js2-LET (js2-name-node-name iter) pn t))
-          (if (js2-must-match js2-IN "msg.in.after.for.name")
-              (setq in-pos (- js2-token-beg pos)))
+          (if (or (js2-match-token js2-IN)
+              (and (>= js2-language-version 200)
+                   (js2-match-token js2-OF)
+                   (setq forof-p t)))
+              (setq in-pos (- js2-token-beg pos))
+            (js2-report-error "msg.in.after.for.name"))
           (setq obj (js2-parse-expr))
           (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
               (setq rp (- js2-token-beg pos)))
@@ -9543,6 +9563,7 @@ Last token peeked should be the initial FOR."
                 (js2-array-comp-loop-node-in-pos pn) in-pos
                 (js2-array-comp-loop-node-each-pos pn) each-pos
                 (js2-array-comp-loop-node-foreach-p pn) foreach-p
+                (js2-array-comp-loop-node-forof-p pn) forof-p
                 (js2-array-comp-loop-node-lp pn) lp
                 (js2-array-comp-loop-node-rp pn) rp)
           (js2-node-add-children pn iter obj))

commit 441da8ce869350162233f5e99b2171eacf403e6c
Merge: 14c6ea5 f22f4bb
Author: Dmitry Gutov <address@hidden>
Date:   Mon Jun 11 12:18:25 2012 +0400

    Merge branch 'master' into emacs24


commit f22f4bbc9bbcd0545ac8fb81ce96f44b0579668e
Author: Francois-Xavier Kowalski <address@hidden>
Date:   Mon Jun 11 12:07:01 2012 +0400

    Add Makefile for byte compiling

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..77e9bba
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+# -*- Makefile -*-
+
+# Compile with noninteractive and relatively clean environment.
+BATCHFLAGS = -batch -q --no-site-file
+
+SRCS = js2-mode.el js2-imenu-extras.el
+
+OBJS = $(SRCS:.el=.elc)
+
+%.elc: %.el
+       emacs $(BATCHFLAGS) -f batch-byte-compile $^
+
+all: $(OBJS)
+
+clean:
+       -rm -f $(OBJS)
+
+# custom build (require loads)
+js2-imenu-extras.elc: js2-mode.elc
+       emacs $(BATCHFLAGS) -l ./js2-mode.elc -f batch-byte-compile $*.el

commit 1b560c6182e181b61bd2dd7e7af5a2bc9c405b79
Author: Dmitry Gutov <address@hidden>
Date:   Mon Jun 11 11:10:57 2012 +0400

    Fix built-in properties highlighting

diff --git a/js2-mode.el b/js2-mode.el
index e41980c..910279d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6408,7 +6408,7 @@ Shown at or above `js2-highlight-level' 3.")
         (js2-set-face (setq pos (+ (js2-node-pos parent) ; absolute
                                    (js2-node-pos prop))) ; relative
                       (+ pos (js2-node-len prop))
-                      face)))))
+                      face 'record)))))
 
 (defun js2-parse-highlight-member-expr-node (node)
   "Perform syntax highlighting of EcmaScript built-in properties.
@@ -6427,7 +6427,7 @@ The variable `js2-highlight-level' governs this 
highighting."
         (when face
           (setq pos (js2-node-pos node)
                 end (+ pos (js2-node-len node)))
-          (js2-set-face pos end face))))
+          (js2-set-face pos end face 'record))))
      ;; case 2:  property access or function call
      ((or (js2-prop-get-node-p node)
           ;; highlight function call if expr is a prop-get node

commit 10f23bd10dc62e9c050a534d38367743d0db863c
Author: Matthew Noorenberghe <address@hidden>
Date:   Sun Jun 10 13:25:51 2012 -0700

    Add ECMA-262 JSON object

diff --git a/js2-mode.el b/js2-mode.el
index 5568c5b..e41980c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -79,7 +79,7 @@
 
 (defvar js2-ecma-262-externs
   (mapcar 'symbol-name
-          '(Array Boolean Date Error EvalError Function Infinity
+          '(Array Boolean Date Error EvalError Function Infinity JSON
           Math NaN Number Object RangeError ReferenceError RegExp
           String SyntaxError TypeError URIError arguments
           decodeURI decodeURIComponent encodeURI
@@ -6353,6 +6353,8 @@ Shown at or above `js2-highlight-level' 2.")
       "toTimeString" "toUTCString"
       ;; properties of the RegExp prototype object
       "exec" "test"
+      ;; properties of the JSON prototype object
+      "parse" "stringify"
       ;; SpiderMonkey/Rhino extensions, versions 1.5+
       "toSource" "__defineGetter__" "__defineSetter__"
       "__lookupGetter__" "__lookupSetter__" "__noSuchMethod__"

commit 0141a2ffade47f43939e27a887306473dcce0c2a
Author: Lawrence Mitchell <address@hidden>
Date:   Sat Jun 9 00:16:58 2012 +0100

    Bump version

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 53c417c..4840f67 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -6,7 +6,7 @@
 ;; Filename: f90-interface-browser.el
 ;; Created: 2011-07-06
 ;; Available-from: http://github.com/wence-/f90-iface/
-;; Version: 1.0
+;; Version: 1.1
 
 ;; COPYRIGHT NOTICE
 

commit 8eaaebcc6874e7f9388987413187df8e9af448d7
Author: Lawrence Mitchell <address@hidden>
Date:   Sat Jun 9 00:16:47 2012 +0100

    Copyright update

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 5746b51..53c417c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -2,7 +2,7 @@
 
 ;; This file is NOT part of Emacs.
 
-;; Copyright (C) 2011 Lawrence Mitchell <address@hidden>
+;; Copyright (C) 2011, 2012 Lawrence Mitchell <address@hidden>
 ;; Filename: f90-interface-browser.el
 ;; Created: 2011-07-06
 ;; Available-from: http://github.com/wence-/f90-iface/

commit 29ee42a4c72e1e9d66a061e0b67bdd25737660fe
Author: Andrew Hyatt <address@hidden>
Date:   Thu Jun 7 23:05:27 2012 -0400

    Add README.org.

diff --git a/README.org b/README.org
new file mode 100644
index 0000000..c4fda04
--- /dev/null
+++ b/README.org
@@ -0,0 +1,8 @@
+This is a elisp library for websocket clients to talk to websocket
+servers. This library is designed to be used by other library writers,
+to write apps that use websockets, and is not useful by itself.
+
+An example of how to use the library is in the
+[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]]
 file.
+
+Currently, this library only supports unencrypted websockets.

commit 4c7276574080d9355eb1673c1e1e6bf787830726
Author: Andrew Hyatt <address@hidden>
Date:   Tue Jun 5 22:41:48 2012 -0400

    Fix up the documentation a bit.

diff --git a/websocket.el b/websocket.el
index 5b1d65b..56fd507 100644
--- a/websocket.el
+++ b/websocket.el
@@ -29,9 +29,11 @@
 ;; struct, and can call methods `websocket-send-text', which sends
 ;; text over the websocket, or `websocket-send', which sends a
 ;; `websocket-frame' struct, enabling finer control of what is sent.
-;; A calback is passed to `websocket-open' that will retrieve
+;; A callback is passed to `websocket-open' that will retrieve
 ;; websocket frames called from the websocket.  Websockets are
 ;; eventually closed with `websocket-close'.
+;;
+;; Currently secure websockets (with wss addresses) are not supported.
 
 (require 'bindat)
 (require 'url-parse)
@@ -50,10 +52,7 @@ API methods are prefixed with \"websocket-\" and take a 
websocket
 as an argument, so the distrinction between the struct API and
 the additional helper APIs are not visible to the caller.
 
-The websocket is created with `websocket-open', which takes a
-url, an optional protocol string, and optional handlers, and
-returns a websocket.  If the protocol is specified, the client
-must support that protocol or the websocket connection will fail.
+A websocket struct is created with `websocket-open'.
 
 `ready-state' contains one of 'connecting, 'open, or
 'closed, depending on the state of the websocket.
@@ -76,12 +75,12 @@ server.
   on-open
   on-message
   on-close
+  server-extensions
 
   ;; Other data - clients should not have to access this.
   (url (assert nil) :read-only t)
   (protocol nil :read-only t)
   (extensions nil :read-only t)
-  server-extensions
   (conn (assert nil) :read-only t)
   (accept-string (assert nil))
   (inflight-input nil))

commit 501b39c4dd806c7215f28eb3a3d14b6ea98e989c
Author: Dmitry Gutov <address@hidden>
Date:   Wed May 2 03:49:10 2012 +0400

    Reduce the indentation variables count
    
    * Remove `js2-consistent-level-indent-inner-bracket-p` (assume it's always 
t).
    * Merge `js2-pretty-multiline-decl-indentation-p` and
      `js2-always-indent-assigned-expr-in-decls-p` into one as
      `js2-pretty-multiline-declarations`.
    * Make the description more clear.
    
    Conflicts:
    
        js2-mode.el: `js2-multiline-decl-indentation` docstring

diff --git a/js2-mode.el b/js2-mode.el
index 923c787..5568c5b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -234,27 +234,24 @@ js2-mode also binds `js2-bounce-indent-backwards' to 
Shift-Tab."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-consistent-level-indent-inner-bracket-p t
-  "Non-nil to make indentation level inner bracket consistent,
-regardless of the beginning bracket position."
-  :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-consistent-level-indent-inner-bracket-p 'booleanp)
+(defcustom js2-pretty-multiline-declarations t
+  "Non-nil to line up multiline declarations vertically:
 
-(defcustom js2-pretty-multiline-decl-indentation-p t
-  "Non-nil to line up multiline declarations vertically. See the
-function `js2-multiline-decl-indentation' for details."
-  :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-pretty-multiline-decl-indentation-p 'booleanp)
+  var a = 10,
+      b = 20,
+      c = 30;
+
+If the value is not `all', and the first assigned value in
+declaration is a function/array/object literal spanning several
+lines, it won't be indented additionally:
 
-(defcustom js2-always-indent-assigned-expr-in-decls-p nil
-  "If both `js2-pretty-multiline-decl-indentation-p' and this are non-nil,
-always additionally indent function expression or array/object literal
-assigned in a declaration, even when only one var is declared."
+  var o = {                   var bar = 2,
+    foo: 3          vs.           o = {
+  },                                foo: 3
+      bar = 2;                    };"
   :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-always-indent-assigned-expr-in-decls-p 'booleanp)
+  :type 'symbol)
+(js2-mark-safe-local 'js2-pretty-multiline-declarations 'symbolp)
 
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.
@@ -9911,22 +9908,8 @@ indented to the same column as the current line."
 
 (defun js2-multiline-decl-indentation ()
   "Returns the declaration indentation column if the current line belongs
-to a multiline declaration statement.  All declarations are lined up 
vertically:
-
-var a = 10,
-    b = 20,
-    c = 30;
-
-Note that if `js2-always-indent-assigned-expr-in-decls-p' is nil, and the first
-assigned expression is a function or array/object literal, it will be indented
-differently:
-
-var o = {                               var bar = 2,
-  foo: 3                                    o = {
-},                                            foo: 3
-    bar = 2;                                };
-"
-  (let (forward-sexp-function ; use lisp version
+to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
+  (let (forward-sexp-function ; use Lisp version
         at-opening-bracket)
     (save-excursion
       (back-to-indentation)
@@ -10022,7 +10005,7 @@ In particular, return the buffer position of the first 
`for' kwd."
     (let ((ctrl-stmt-indent (js2-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
           (continued-expr-p (js2-continued-expression-p))
-          (declaration-indent (and js2-pretty-multiline-decl-indentation-p
+          (declaration-indent (and js2-pretty-multiline-declarations
                                    (js2-multiline-decl-indentation)))
           (bracket (nth 1 parse-status))
           beg)
@@ -10048,25 +10031,19 @@ In particular, return the buffer position of the 
first `for' kwd."
         (goto-char bracket)
         (cond
          ((looking-at "[({[][ \t]*\\(/[/*]\\|$\\)")
-          (let ((p (parse-partial-sexp (point-at-bol) (point))))
-            (when (save-excursion (skip-chars-backward " \t)")
-                                  (looking-at ")"))
-              (backward-list))
-            (if (and (nth 1 p)
-                     (not js2-consistent-level-indent-inner-bracket-p))
-                (progn (goto-char (1+ (nth 1 p)))
-                       (skip-chars-forward " \t"))
-              (back-to-indentation)
-              (when (and js2-pretty-multiline-decl-indentation-p
-                         js2-always-indent-assigned-expr-in-decls-p
-                         (looking-at js2-declaration-keyword-re))
-                (goto-char (1+ (match-end 0)))))
-            (cond (same-indent-p
-                   (current-column))
-                  (continued-expr-p
-                   (+ (current-column) (* 2 js2-basic-offset)))
-                  (t
-                   (+ (current-column) js2-basic-offset)))))
+          (when (save-excursion (skip-chars-backward " \t)")
+                                (looking-at ")"))
+            (backward-list))
+          (back-to-indentation)
+          (and (eq js2-pretty-multiline-declarations 'all)
+               (looking-at js2-declaration-keyword-re)
+               (goto-char (1+ (match-end 0))))
+          (cond (same-indent-p
+                 (current-column))
+                (continued-expr-p
+                 (+ (current-column) (* 2 js2-basic-offset)))
+                (t
+                 (+ (current-column) js2-basic-offset))))
          (t
           (unless same-indent-p
             (forward-char)

commit 84f4795fc93c7727e3a23eb9205750ca0f644fc2
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 6 03:13:42 2012 +0400

    Make `js2-parse-primary-expr-lhs` a defun
    
    Closes #43

diff --git a/js2-mode.el b/js2-mode.el
index bfd7549..923c787 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9261,7 +9261,7 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
                                           :rb (js2-relpos rb pos)))
       (js2-node-add-children pn namespace expr))))
 
-(defsubst js2-parse-primary-expr-lhs ()
+(defun js2-parse-primary-expr-lhs ()
   (let ((js2-is-in-lhs t))
     (js2-parse-primary-expr)))
 

commit ee845b34abc0d3c43491ac2e4f18bc02de5bdbe4
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jun 6 03:12:42 2012 +0400

    Use consistent package prefix for all vars

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 50625c9..f9215a4 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -117,7 +117,7 @@ prefix any functions defined inside the IIFE with the 
module name."
          ;; Dynamic scoping. Ew.
          (js2-mode-ast root))
     (goto-char (point-min))
-    (while (js-re-search-forward re nil t)
+    (while (js2-re-search-forward re nil t)
       (loop for i from 0 to (1- (length styles))
             when (match-beginning (1+ i))
             return (funcall (plist-get (nth i styles) :recorder))))))
diff --git a/js2-mode.el b/js2-mode.el
index c9decde..bfd7549 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -243,7 +243,7 @@ regardless of the beginning bracket position."
 
 (defcustom js2-pretty-multiline-decl-indentation-p t
   "Non-nil to line up multiline declarations vertically. See the
-function `js-multiline-decl-indentation' for details."
+function `js2-multiline-decl-indentation' for details."
   :group 'js2-mode
   :type 'boolean)
 (js2-mark-safe-local 'js2-pretty-multiline-decl-indentation-p 'booleanp)
@@ -8339,7 +8339,7 @@ Last token matched must be js2-LC."
 ;; for js2-ERROR too, to have a node for error recovery to work on
 (defun js2-parse-semi ()
   "Parse a statement or handle an error.
-Last matched token is js-SEMI or js-ERROR."
+Last matched token is js2-SEMI or js2-ERROR."
   (let ((tt (js2-peek-token)) pos len)
     (js2-consume-token)
     (if (eq tt js2-SEMI)
@@ -9739,20 +9739,20 @@ not `js2-NAME', then we use the token info saved in 
instance vars."
 ;; Karl for coming up with the initial approach, which packs a lot of
 ;; punch for so little code.
 
-(defconst js-possibly-braceless-keywords-re
+(defconst js2-possibly-braceless-keywords-re
   (concat "else[ \t]+if\\|for[ \t]+each\\|"
           (regexp-opt '("catch" "do" "else" "finally" "for" "if"
                         "try" "while" "with" "let")))
   "Regular expression matching keywords that are optionally
 followed by an opening brace.")
 
-(defconst js-indent-operator-re
+(defconst js2-indent-operator-re
   (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
           (regexp-opt '("in" "instanceof") 'words))
   "Regular expression matching operators that affect indentation
 of continued expressions.")
 
-(defconst js-declaration-keyword-re
+(defconst js2-declaration-keyword-re
   (regexp-opt '("var" "let" "const") 'words)
   "Regular expression matching variable declaration keywords.")
 
@@ -9778,8 +9778,8 @@ bound to KEY in the global keymap and indents the current 
line."
                 (nth 4 parse-state))
       (indent-according-to-mode))))
 
-(defun js-re-search-forward-inner (regexp &optional bound count)
-  "Auxiliary function for `js-re-search-forward'."
+(defun js2-re-search-forward-inner (regexp &optional bound count)
+  "Auxiliary function for `js2-re-search-forward'."
   (let (parse saved-point)
     (while (> count 0)
       (re-search-forward regexp bound)
@@ -9800,18 +9800,18 @@ bound to KEY in the global keymap and indents the 
current line."
       (setq saved-point (point))))
   (point))
 
-(defun js-re-search-forward (regexp &optional bound noerror count)
+(defun js2-re-search-forward (regexp &optional bound noerror count)
   "Search forward but ignore strings and comments. Invokes
 `re-search-forward' but treats the buffer as if strings and
 comments have been removed."
   (let ((saved-point (point))
         (search-expr
          (cond ((null count)
-                '(js-re-search-forward-inner regexp bound 1))
+                '(js2-re-search-forward-inner regexp bound 1))
                ((< count 0)
-                '(js-re-search-backward-inner regexp bound (- count)))
+                '(js2-re-search-backward-inner regexp bound (- count)))
                ((> count 0)
-                '(js-re-search-forward-inner regexp bound count)))))
+                '(js2-re-search-forward-inner regexp bound count)))))
     (condition-case err
         (eval search-expr)
       (search-failed
@@ -9819,8 +9819,8 @@ comments have been removed."
        (unless noerror
          (error (error-message-string err)))))))
 
-(defun js-re-search-backward-inner (regexp &optional bound count)
-  "Auxiliary function for `js-re-search-backward'."
+(defun js2-re-search-backward-inner (regexp &optional bound count)
+  "Auxiliary function for `js2-re-search-backward'."
   (let (parse saved-point)
     (while (> count 0)
       (re-search-backward regexp bound)
@@ -9840,18 +9840,18 @@ comments have been removed."
              (setq count (1- count))))))
   (point))
 
-(defun js-re-search-backward (regexp &optional bound noerror count)
+(defun js2-re-search-backward (regexp &optional bound noerror count)
   "Search backward but ignore strings and comments. Invokes
 `re-search-backward' but treats the buffer as if strings and
 comments have been removed."
   (let ((saved-point (point))
         (search-expr
          (cond ((null count)
-                '(js-re-search-backward-inner regexp bound 1))
+                '(js2-re-search-backward-inner regexp bound 1))
                ((< count 0)
-                '(js-re-search-forward-inner regexp bound (- count)))
+                '(js2-re-search-forward-inner regexp bound (- count)))
                ((> count 0)
-                '(js-re-search-backward-inner regexp bound count)))))
+                '(js2-re-search-backward-inner regexp bound count)))))
     (condition-case err
         (eval search-expr)
       (search-failed
@@ -9859,33 +9859,33 @@ comments have been removed."
        (unless noerror
          (error (error-message-string err)))))))
 
-(defun js-looking-at-operator-p ()
+(defun js2-looking-at-operator-p ()
   "Return non-nil if text after point is an operator (that is not
 a comma)."
   (save-match-data
-    (and (looking-at js-indent-operator-re)
+    (and (looking-at js2-indent-operator-re)
          (or (not (looking-at ":"))
              (save-excursion
-               (and (js-re-search-backward "[?:{]\\|\\<case\\>" nil t)
+               (and (js2-re-search-backward "[?:{]\\|\\<case\\>" nil t)
                     (looking-at "?")))))))
 
-(defun js-continued-expression-p ()
+(defun js2-continued-expression-p ()
   "Returns non-nil if the current line continues an expression."
   (save-excursion
     (back-to-indentation)
-    (or (js-looking-at-operator-p)
+    (or (js2-looking-at-operator-p)
         ;; comment
-        (and (js-re-search-backward "\n" nil t)
+        (and (js2-re-search-backward "\n" nil t)
             (progn
               (skip-chars-backward " \t")
                (unless (bolp)
                  (backward-char)
-                 (and (js-looking-at-operator-p)
+                 (and (js2-looking-at-operator-p)
                       (and (progn
                              (backward-char)
                              (not (looking-at 
"\\*\\|++\\|--\\|/[/*]")))))))))))
 
-(defun js-end-of-do-while-loop-p ()
+(defun js2-end-of-do-while-loop-p ()
   "Returns non-nil if word after point is `while' of a do-while
 statement, else returns nil. A braceless do-while statement
 spanning several lines requires that the start of the loop is
@@ -9899,17 +9899,17 @@ indented to the same column as the current line."
              (looking-at "[ \t\n]*}"))
            (save-excursion
              (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
-         (js-re-search-backward "\\<do\\>" (point-at-bol) t)
+         (js2-re-search-backward "\\<do\\>" (point-at-bol) t)
          (or (looking-at "\\<do\\>")
              (let ((saved-indent (current-indentation)))
-               (while (and (js-re-search-backward "^[ \t]*\\<" nil t)
+               (while (and (js2-re-search-backward "^[ \t]*\\<" nil t)
                            (/= (current-indentation) saved-indent)))
                (and (looking-at "[ \t]*\\<do\\>")
-                    (not (js-re-search-forward
+                    (not (js2-re-search-forward
                           "\\<while\\>" (point-at-eol) t))
                     (= (current-indentation) saved-indent)))))))))
 
-(defun js-multiline-decl-indentation ()
+(defun js2-multiline-decl-indentation ()
   "Returns the declaration indentation column if the current line belongs
 to a multiline declaration statement.  All declarations are lined up 
vertically:
 
@@ -9930,8 +9930,8 @@ var o = {                               var bar = 2,
         at-opening-bracket)
     (save-excursion
       (back-to-indentation)
-      (when (not (looking-at js-declaration-keyword-re))
-        (when (looking-at js-indent-operator-re)
+      (when (not (looking-at js2-declaration-keyword-re))
+        (when (looking-at js2-indent-operator-re)
           (goto-char (match-end 0))) ; continued expressions are ok
         (while (and (not at-opening-bracket)
                     (not (bobp))
@@ -9942,17 +9942,17 @@ var o = {                               var bar = 2,
                             (and (not (eq (char-before) ?\;))
                                  (and
                                   (prog2 (skip-chars-backward "[[:punct:]]")
-                                      (looking-at js-indent-operator-re)
+                                      (looking-at js2-indent-operator-re)
                                     (js2-backward-sws))
                                   (not (eq (char-before) ?\;))))
                             (js2-same-line pos)))))
           (condition-case err
               (backward-sexp)
             (scan-error (setq at-opening-bracket t))))
-        (when (looking-at js-declaration-keyword-re)
+        (when (looking-at js2-declaration-keyword-re)
           (- (1+ (match-end 0)) (point-at-bol)))))))
 
-(defun js-ctrl-statement-indentation ()
+(defun js2-ctrl-statement-indentation ()
   "Returns the proper indentation of the current line if it
 starts the body of a control statement without braces, else
 returns nil."
@@ -9961,7 +9961,7 @@ returns nil."
       (back-to-indentation)
       (when (and (not (js2-same-line (point-min)))
                  (not (looking-at "{"))
-                 (js-re-search-backward "[[:graph:]]" nil t)
+                 (js2-re-search-backward "[[:graph:]]" nil t)
                  (not (looking-at "[{([]"))
                  (progn
                    (forward-char)
@@ -9971,9 +9971,9 @@ returns nil."
                      (skip-chars-backward " \t" (point-at-bol)))
                    (let ((pt (point)))
                      (back-to-indentation)
-                     (and (looking-at js-possibly-braceless-keywords-re)
+                     (and (looking-at js2-possibly-braceless-keywords-re)
                           (= (match-end 0) pt)
-                          (not (js-end-of-do-while-loop-p))))))
+                          (not (js2-end-of-do-while-loop-p))))))
         (+ (current-indentation) js2-basic-offset)))))
 
 (defun js2-indent-in-array-comp (parse-status)
@@ -10015,15 +10015,15 @@ In particular, return the buffer position of the 
first `for' kwd."
       (goto-char for-kwd)
       (current-column))))
 
-(defun js-proper-indentation (parse-status)
+(defun js2-proper-indentation (parse-status)
   "Return the proper indentation for the current line."
   (save-excursion
     (back-to-indentation)
-    (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
+    (let ((ctrl-stmt-indent (js2-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
-          (continued-expr-p (js-continued-expression-p))
+          (continued-expr-p (js2-continued-expression-p))
           (declaration-indent (and js2-pretty-multiline-decl-indentation-p
-                                   (js-multiline-decl-indentation)))
+                                   (js2-multiline-decl-indentation)))
           (bracket (nth 1 parse-status))
           beg)
       (cond
@@ -10059,7 +10059,7 @@ In particular, return the buffer position of the first 
`for' kwd."
               (back-to-indentation)
               (when (and js2-pretty-multiline-decl-indentation-p
                          js2-always-indent-assigned-expr-in-decls-p
-                         (looking-at js-declaration-keyword-re))
+                         (looking-at js2-declaration-keyword-re))
                 (goto-char (1+ (match-end 0)))))
             (cond (same-indent-p
                    (current-column))
@@ -10371,7 +10371,7 @@ If so, we don't ever want to use bounce-indent."
     (js2-with-underscore-as-word-syntax
      (if (nth 4 parse-status)
          (js2-lineup-comment parse-status)
-       (setq indent-col (js-proper-indentation parse-status))
+       (setq indent-col (js2-proper-indentation parse-status))
        ;; see comments below about js2-mode-last-indented-line
        (cond
         ;; bounce-indenting is disabled during electric-key indent.

commit 06b72725d2b3760edd7d2caae93367593b395253
Author: Andrew Hyatt <address@hidden>
Date:   Sun Jun 3 23:42:34 2012 -0400

    Fix obsolete code in websocket-ensure-connected, and removed dependency on 
CL.
    
    websocket.el now byte-compiles cleanly again.

diff --git a/websocket.el b/websocket.el
index 9c4d16a..5b1d65b 100644
--- a/websocket.el
+++ b/websocket.el
@@ -459,10 +459,12 @@ of populating the list of server extensions to WEBSOCKET."
           (setq extensions (append extensions (split-string
                                                (match-string 1 output) ", 
?")))))
       (let ((extra-extensions
-             (set-difference (mapcar (lambda (ext) (first (split-string ext "; 
?")))
-                                     extensions)
-                             (websocket-extensions websocket)
-                             :test 'equal)))
+             (mapcan (lambda (ext) (when (not
+                                     (member
+                                      (first (split-string ext "; ?"))
+                                      (websocket-extensions websocket)))
+                                (list (first (split-string ext "; ?")))))
+                     extensions)))
         (when extra-extensions
           (error "Non-requested extensions returned by server: %s"
                  extra-extensions)))
@@ -579,8 +581,11 @@ connecting or open."
                  ((stop exit signal closed connect failed nil) nil)))
     (websocket-close websocket)
     (websocket-open (websocket-url websocket)
-                      (websocket-filter websocket)
-                      (websocket-close-callback websocket))))
+                    :protocol (websocket-protocol websocket)
+                    :extensions (websocket-extensions websocket)
+                    :on-open (websocket-on-open websocket)
+                    :on-message (websocket-on-message websocket)
+                    :on-close (websocket-on-close websocket))))
 
 (provide 'websocket)
 

commit 14c6ea539b9ee7b98d0c6b870c23202798ba37b3
Author: Dmitry Gutov <address@hidden>
Date:   Mon Jun 4 03:54:01 2012 +0400

    Bring back js2-external-variable face
    
    Being able to distinguish this type of warning from others is kinda useful.
    
    Might also use overriding for new types of warnings later, like unused vars.

diff --git a/js2-mode.el b/js2-mode.el
index fb6cd17..56dac13 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1104,6 +1104,9 @@ Not currently used."
   "Face used to highlight brackets in jsdoc html tags."
   :group 'js2-mode)
 
+(defface js2-external-variable
+  '((t :foreground "orange"))
+  "Face used to highlight undeclared variable identifiers.")
 
 (defcustom js2-post-parse-callbacks nil
   "A list of callback functions invoked after parsing finishes.
@@ -2010,12 +2013,13 @@ Returns nil if element is not found in the list."
                   (current-column))
                 js2-ts-hit-eof))))
 
-(defun js2-report-warning (msg &optional msg-arg pos len)
+(defun js2-report-warning (msg &optional msg-arg pos len face)
   (if js2-compiler-report-warning-as-error
       (js2-report-error msg msg-arg pos len)
     (push (list (list msg msg-arg)
                 (or pos js2-token-beg)
-                (or len (- js2-token-end js2-token-beg)))
+                (or len (- js2-token-end js2-token-beg))
+                face)
           js2-parsed-warnings)))
 
 (defun js2-add-strict-warning (msg-id &optional msg-arg beg end)
@@ -6486,7 +6490,8 @@ it is considered declared."
                     (member name js2-default-externs)
                     (member name js2-additional-externs)
                     (js2-get-defining-scope scope name))
-          (js2-report-warning "msg.undeclared.variable" name pos (- end 
pos)))))
+          (js2-report-warning "msg.undeclared.variable" name pos (- end pos)
+                              'js2-external-variable))))
     (setq js2-recorded-identifiers nil)))
 
 ;;; IMenu support
@@ -10464,7 +10469,8 @@ P1 and P2 are the old and new values of point, 
respectively."
 
 (defun js2-mode-show-warn-or-err (e face)
   "Highlight a warning or error E with FACE.
-E is a list of ((MSG-KEY MSG-ARG) BEG END)."
+E is a list of ((MSG-KEY MSG-ARG) BEG LEN OVERRIDE-FACE).
+The last element is optional.  When present, use instead of FACE."
   (let* ((key (first e))
          (beg (second e))
          (end (+ beg (third e)))
@@ -10473,7 +10479,7 @@ E is a list of ((MSG-KEY MSG-ARG) BEG END)."
          (end (max (point-min) (min end (point-max))))
          (js2-highlight-level 3)    ; so js2-set-face is sure to fire
          (ovl (make-overlay beg end)))
-    (overlay-put ovl 'font-lock-face face)
+    (overlay-put ovl 'font-lock-face (or (fourth e) face))
     (overlay-put ovl 'js2-error t)
     (put-text-property beg end 'help-echo (js2-get-msg key))
     (put-text-property beg end 'point-entered #'js2-echo-error)))

commit db22d53b4e2dc16de057d6bf423002299be1fc3b
Author: Dmitry Gutov <address@hidden>
Date:   Mon Jun 4 03:35:57 2012 +0400

    Wrap all `js2-post-parse-callbacks` calls in (save-excursion)

diff --git a/js2-mode.el b/js2-mode.el
index 64ad3a5..fb6cd17 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7182,8 +7182,9 @@ Scanner should be initialized."
     (setf (js2-node-len root) (- end pos))
     ;; Give extensions a chance to muck with things before highlighting starts.
     (let ((js2-additional-externs js2-additional-externs))
-      (dolist (callback js2-post-parse-callbacks)
-        (funcall callback))
+      (save-excursion
+        (dolist (callback js2-post-parse-callbacks)
+          (funcall callback)))
       (js2-highlight-undeclared-vars))
     root))
 

commit 20995f67febf797469872fd95bb8f8f2ff03fd78
Merge: 32a113a 262bf9d
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 21:37:23 2012 +0400

    Merge branch 'master' into emacs24
    
    Conflicts:
        js2-mode.el

diff --cc js2-imenu-extras.el
index 0000000,50625c9..f9215a4
mode 000000,100644..100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@@ -1,0 -1,215 +1,215 @@@
+ ;;; js2-imenu-extras.el --- Imenu support for additional constructs
+ 
+ ;; Author:    Dmitry Gutov <address@hidden>
+ ;; Keywords:  languages, javascript, imenu
+ 
+ ;; This file is part of GNU Emacs.
+ 
+ ;; GNU Emacs is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; (at your option) any later version.
+ 
+ ;; GNU Emacs is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ ;; GNU General Public License for more details.
+ 
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+ 
+ ;;; Commentary:
+ 
+ ;; This package adds Imenu support for additional framework constructs and
+ ;; general patterns to `js2-mode'.
+ 
+ ;; Usage:
+ 
+ ;; (eval-after-load 'js2-mode
+ ;;   '(progn
+ ;;      (require 'js2-imenu-extras)
+ ;;      (js2-imenu-extras-setup)))
+ 
+ ;; To customize how it works:
+ ;;   M-x customize-group RET js2-imenu RET
+ 
+ (eval-when-compile
+   (require 'cl))
+ 
+ (require 'js2-mode)
+ 
+ (defconst js2-imenu-extension-styles
+   `((:framework jquery
+      :call-re   "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
+      :recorder  js2-imenu-record-jquery-extend)
+ 
+     (:framework jquery-ui
+      :call-re   "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
+      :recorder  js2-imenu-record-string-declare)
+ 
+     (:framework dojo
+      :call-re   "^\\s-*dojo.declare\\s-*("
+      :recorder  js2-imenu-record-string-declare)
+ 
+     (:framework backbone
+      :call-re   ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
+      :recorder  js2-imenu-record-backbone-extend))
+   "List of JavaScript class definition or extension styles.
+ 
+ :framework is a valid value in `js2-imenu-enabled-frameworks'.
+ 
+ :call-re is a regular expression that has no capturing groups.
+ 
+ :recorder is a function name that will be called when the regular
+ expression matches some text in the buffer.  When it's called, point will be
+ at the end of the match.  The function must keep the point position.")
+ 
+ (defconst js2-imenu-available-frameworks
+   (mapcar (lambda (style) (plist-get style :framework)) 
js2-imenu-extension-styles)
+   "List of available JavaScript framework symbols.")
+ 
+ (defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
+   "Frameworks to be recognized by `js2-mode'."
+   :type (cons 'set (mapcar (lambda (x) (list 'const x))
+                            js2-imenu-available-frameworks))
+   :group 'js2-imenu)
+ 
+ (defcustom js2-imenu-show-other-functions t
+   "Non-nil to show functions not recognized by other mechanisms,
+ in a shared namespace."
+   :type 'boolean
+   :group 'js2-imenu)
+ 
+ (defcustom js2-imenu-other-functions-ns "?"
+   "Namespace name to use for other functions."
+   :type 'string
+   :group 'js2-imenu)
+ 
+ (defcustom js2-imenu-show-module-pattern t
+   "Non-nil to recognize the module pattern:
+ 
+ var foobs = (function(a) {
+   return {fib: function() {}, fub: function() {}};
+ })(b);
+ 
+ We record the returned hash as belonging to the named module, and
+ prefix any functions defined inside the IIFE with the module name."
+   :type 'boolean
+   :group 'js2-imenu)
+ 
+ ;;;###autoload
+ (defun js2-imenu-extras-setup ()
+   (when js2-imenu-enabled-frameworks
+     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
+   (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
+     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))
+ 
+ (declare (special root))
+ 
+ (defun js2-imenu-record-declarations ()
+   (let* ((styles (loop for style in js2-imenu-extension-styles
+                        when (memq (plist-get style :framework)
+                                   js2-imenu-enabled-frameworks)
+                        collect style))
+          (re (mapconcat (lambda (style)
+                           (concat "\\(" (plist-get style :call-re) "\\)"))
+                         styles "\\|"))
+          ;; Dynamic scoping. Ew.
+          (js2-mode-ast root))
+     (goto-char (point-min))
 -    (while (js-re-search-forward re nil t)
++    (while (js2-re-search-forward re nil t)
+       (loop for i from 0 to (1- (length styles))
+             when (match-beginning (1+ i))
+             return (funcall (plist-get (nth i styles) :recorder))))))
+ 
+ (defun js2-imenu-record-jquery-extend ()
+   (let ((pred (lambda (subject)
+                 (and
+                  (js2-prop-get-node-p subject)
+                  (string= (js2-name-node-name (js2-prop-get-node-right 
subject))
+                           "prototype")))))
+     (js2-imenu-record-extend-first-arg (1- (point)) pred
+                                        'js2-compute-nested-prop-get)))
+ 
+ (defun js2-imenu-record-string-declare ()
+   (js2-imenu-record-extend-first-arg
+    (1- (point)) 'js2-string-node-p
+    (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
+ 
+ (defun js2-imenu-record-extend-first-arg (point pred qname-fn)
+   (let* ((node (js2-node-at-point point))
+          (args (js2-call-node-args node))
+          (subject (first args)))
+     (when (funcall pred subject)
+       (loop for arg in (cdr args)
+             when (js2-object-node-p arg)
+             do (js2-record-object-literal
+                 arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
+ 
+ (defun js2-imenu-record-backbone-extend ()
+   (let* ((node (js2-node-at-point (1- (point))))
+          (args (js2-call-node-args node))
+          (methods (first args))
+          (parent (js2-node-parent node)))
+     (when (js2-object-node-p methods)
+       (let ((subject (cond ((js2-var-init-node-p parent)
+                             (js2-var-init-node-target parent))
+                            ((js2-assign-node-p parent)
+                             (js2-assign-node-left parent)))))
+         (when subject
+           (js2-record-object-literal methods
+                                      (js2-compute-nested-prop-get subject)
+                                      (js2-node-abs-pos methods)))))))
+ 
+ (defun js2-imenu-walk-ast ()
+   (js2-visit-ast
+    root
+    (lambda (node end-p)
+      (unless end-p
+        (cond
+         ((and js2-imenu-show-other-functions
+               (js2-object-prop-node-p node))
+          (js2-imenu-record-orphan-function node))
+         ((and js2-imenu-show-module-pattern
+               (js2-assign-node-p node))
+          (js2-imenu-record-module-pattern node)))
+        t))))
+ 
+ (defun js2-imenu-record-orphan-function (node)
+   "Record orphan function when it's the value of NODE.
+ NODE must be `js2-object-prop-node'."
+   (when (js2-function-node-p (js2-object-prop-node-right node))
+     (let ((fn-node (js2-object-prop-node-right node)))
+       (unless (and js2-imenu-function-map
+                    (gethash fn-node js2-imenu-function-map))
+         (let ((key-node (js2-object-prop-node-left node)))
+           (js2-record-imenu-entry fn-node
+                                   (list js2-imenu-other-functions-ns
+                                         (js2-prop-node-name key-node))
+                                   (js2-node-abs-pos key-node)))))))
+ 
+ (defun js2-imenu-record-module-pattern (node)
+   "Recognize and record module pattern use instance.
+ NODE must be `js2-assign-node'."
+   (let ((init (js2-assign-node-right node)))
+     (when (js2-call-node-p init)
+       (let ((target (js2-assign-node-left node))
+             (callt (js2-call-node-target init)))
+         ;; Just basic call form: (function() {...})();
+         ;; TODO: Handle variations without duplicating 
`js2-wrapper-function-p'?
+         (when (and (js2-paren-node-p callt)
+                    (js2-function-node-p (js2-paren-node-expr callt)))
+           (let* ((fn (js2-paren-node-expr callt))
+                  (blk (js2-function-node-body fn))
+                  (ret (car (last (js2-block-node-kids blk)))))
+             (when (and (js2-return-node-p ret)
+                        (js2-object-node-p (js2-return-node-retval ret)))
+               ;; TODO: Map function names when revealing module pattern is 
used.
+               (let ((retval (js2-return-node-retval ret))
+                     (target-qname (js2-compute-nested-prop-get target)))
+                 (js2-record-object-literal retval target-qname
+                                            (js2-node-abs-pos retval))
+                 (js2-record-imenu-entry fn target-qname
+                                         (js2-node-abs-pos target))))))))))
+ 
+ (provide 'js2-imenu-extras)
diff --cc js2-mode.el
index 974bcdd,c9decde..64ad3a5
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -10559,14 -10746,19 +10556,16 @@@ This ensures that the counts and `next-
  
  (defalias #'js2-echo-help #'js2-echo-error)
  
 -(defun js2-enter-key ()
 -  "Handle user pressing the Enter key."
 -  (interactive)
 -  (let ((parse-status (save-excursion
 -                        (syntax-ppss (point))))
 -        (js2-bounce-indent-p nil))
 +(defun js2-line-break (&optional soft)
 +  "Break line at point."
 +  (let ((parse-status (syntax-ppss)))
      (cond
 -     ;; check if we're inside a string
 +     ;; Check if we're inside a string.
       ((nth 3 parse-status)
-       (js2-mode-split-string parse-status))
+       (if js2-concat-multiline-strings
+           (js2-mode-split-string parse-status)
+         (insert "\n")))
 -     ;; check if inside a block comment
 +     ;; Check if inside a block comment.
       ((nth 4 parse-status)
        (js2-mode-extend-comment))
       (t
@@@ -10579,19 -10776,27 +10578,26 @@@ PARSE-STATUS is as documented in `parse
           (quote-char (nth 3 parse-status))
           (quote-string (string quote-char))
           (string-beg (nth 8 parse-status))
+          (at-eol (eq js2-concat-multiline-strings 'eol))
 -         (indent (save-match-data
 -                   (or
 -                    (save-excursion
 -                      (back-to-indentation)
 -                      (if (looking-at "\\+")
 -                          (current-column)))
 -                    (save-excursion
 -                      (goto-char string-beg)
 -                      (if (looking-back "\\+\\s-+")
 -                          (goto-char (match-beginning 0)))
 -                      (current-column))))))
 +         (indent (or
 +                  (save-excursion
 +                    (back-to-indentation)
 +                    (if (looking-at "\\+")
 +                        (current-column)))
 +                  (save-excursion
 +                    (goto-char string-beg)
 +                    (if (looking-back "\\+\\s-+")
 +                        (goto-char (match-beginning 0)))
 +                    (current-column)))))
-     (insert quote-char "\n")
+     (insert quote-char)
+     (if at-eol
+         (insert " +\n")
+       (insert "\n"))
+     ;; FIXME: This does not match the behavior of `js2-indent-line'.
      (indent-to indent)
-     (insert "+ " quote-string)
+     (unless at-eol
+       (insert "+ "))
+     (insert quote-string)
      (when (eolp)
        (insert quote-string)
        (backward-char 1))))

commit 262bf9d41456ebd90f4e59c82feb24ef9a5f98cd
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 20:05:19 2012 +0400

    Forgot a single quote

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 7f026c5..50625c9 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -56,7 +56,7 @@
      :recorder  js2-imenu-record-backbone-extend))
   "List of JavaScript class definition or extension styles.
 
-:framework is a valid value in `js2-imenu-enabled-frameworks.
+:framework is a valid value in `js2-imenu-enabled-frameworks'.
 
 :call-re is a regular expression that has no capturing groups.
 

commit 71c60bb15cbe04a3a26c017bdb7d683623eda53e
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jun 2 23:24:21 2012 -0400

    Fixed several bugs in `websocket-open'.
    
    The port was not being retrieved in the correct way, and the websocket
    state change code was incorrectly positioned.

diff --git a/websocket.el b/websocket.el
index bd44932..9c4d16a 100644
--- a/websocket.el
+++ b/websocket.el
@@ -318,7 +318,9 @@ variable `websocket-debug' to t."
                    (make-network-process :name name
                                          :buffer buf-name
                                          :host (url-host url-struct)
-                                         :service (url-port url-struct)
+                                         :service (if (= 0 (url-port 
url-struct))
+                                                      80
+                                                    (url-port url-struct))
                                          :nowait nil)
                  (if (equal (url-type url-struct) "wss")
                      (error "Not implemented yet")
@@ -343,14 +345,14 @@ variable `websocket-debug' to t."
      (lambda (process change)
        (let ((websocket (process-get process :websocket)))
          (websocket-debug websocket
-                          "State change to %s" change))
-       (unless (eq 'closed (websocket-ready-state websocket))
-         (condition-case err
-             (funcall (websocket-on-close websocket)
-                      websocket)
-           (error (websocket-error
-                   websocket
-                   "Got error from the op-close function: %s"))))))
+                          "State change to %s" change)
+         (unless (eq 'closed (websocket-ready-state websocket))
+           (condition-case err
+               (funcall (websocket-on-close websocket)
+                        websocket)
+             (error (websocket-error
+                     websocket
+                     "Got error from the op-close function: %s")))))))
     (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"

commit 41f0eb9581c157a63abab6b83f968ffb689b2e62
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 06:16:29 2012 +0400

    js2-imenu-extras: Fix usage example

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index b895cfa..7f026c5 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -26,8 +26,9 @@
 ;; Usage:
 
 ;; (eval-after-load 'js2-mode
-;;   (require 'js2-imenu-extras)
-;;   (js2-imenu-extras-setup))
+;;   '(progn
+;;      (require 'js2-imenu-extras)
+;;      (js2-imenu-extras-setup)))
 
 ;; To customize how it works:
 ;;   M-x customize-group RET js2-imenu RET

commit deb1ab085cddd8b6de24e62f869297adca355cd4
Merge: 81bcbf7 eb482e2
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 06:11:27 2012 +0400

    Merge branch 'imenu'


commit eb482e23d37d37d6e81460c210caddd710c2216c
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 06:09:14 2012 +0400

    Fix recorded module function node position

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index f6a0d2f..b895cfa 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -204,10 +204,11 @@ NODE must be `js2-assign-node'."
             (when (and (js2-return-node-p ret)
                        (js2-object-node-p (js2-return-node-retval ret)))
               ;; TODO: Map function names when revealing module pattern is 
used.
-              (let ((retval (js2-return-node-retval ret)))
-                (js2-record-object-literal retval
-                                           (js2-compute-nested-prop-get target)
-                                           (js2-node-abs-pos retval)))
-              (js2-record-imenu-functions fn target))))))))
+              (let ((retval (js2-return-node-retval ret))
+                    (target-qname (js2-compute-nested-prop-get target)))
+                (js2-record-object-literal retval target-qname
+                                           (js2-node-abs-pos retval))
+                (js2-record-imenu-entry fn target-qname
+                                        (js2-node-abs-pos target))))))))))
 
 (provide 'js2-imenu-extras)

commit 534ed78109065890d8845f0b95b2af61cf24a5b3
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 05:29:55 2012 +0400

    Add comments

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 32bfce3..f6a0d2f 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -1,3 +1,37 @@
+;;; js2-imenu-extras.el --- Imenu support for additional constructs
+
+;; Author:    Dmitry Gutov <address@hidden>
+;; Keywords:  languages, javascript, imenu
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package adds Imenu support for additional framework constructs and
+;; general patterns to `js2-mode'.
+
+;; Usage:
+
+;; (eval-after-load 'js2-mode
+;;   (require 'js2-imenu-extras)
+;;   (js2-imenu-extras-setup))
+
+;; To customize how it works:
+;;   M-x customize-group RET js2-imenu RET
+
 (eval-when-compile
   (require 'cl))
 
@@ -18,7 +52,16 @@
 
     (:framework backbone
      :call-re   ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
-     :recorder  js2-imenu-record-backbone-extend)))
+     :recorder  js2-imenu-record-backbone-extend))
+  "List of JavaScript class definition or extension styles.
+
+:framework is a valid value in `js2-imenu-enabled-frameworks.
+
+:call-re is a regular expression that has no capturing groups.
+
+:recorder is a function name that will be called when the regular
+expression matches some text in the buffer.  When it's called, point will be
+at the end of the match.  The function must keep the point position.")
 
 (defconst js2-imenu-available-frameworks
   (mapcar (lambda (style) (plist-get style :framework)) 
js2-imenu-extension-styles)
@@ -28,18 +71,18 @@
   "Frameworks to be recognized by `js2-mode'."
   :type (cons 'set (mapcar (lambda (x) (list 'const x))
                            js2-imenu-available-frameworks))
-  :group 'js2-mode)
+  :group 'js2-imenu)
 
 (defcustom js2-imenu-show-other-functions t
   "Non-nil to show functions not recognized by other mechanisms,
 in a shared namespace."
   :type 'boolean
-  :group 'js2-mode)
+  :group 'js2-imenu)
 
 (defcustom js2-imenu-other-functions-ns "?"
   "Namespace name to use for other functions."
   :type 'string
-  :group 'js2-mode)
+  :group 'js2-imenu)
 
 (defcustom js2-imenu-show-module-pattern t
   "Non-nil to recognize the module pattern:
@@ -51,8 +94,9 @@ var foobs = (function(a) {
 We record the returned hash as belonging to the named module, and
 prefix any functions defined inside the IIFE with the module name."
   :type 'boolean
-  :group 'js2-mode)
+  :group 'js2-imenu)
 
+;;;###autoload
 (defun js2-imenu-extras-setup ()
   (when js2-imenu-enabled-frameworks
     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))

commit 75be74d7c8f6f4c138d609ad407c78fdf7a873d5
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jun 2 21:25:21 2012 -0400

    Added some library documentation

diff --git a/websocket.el b/websocket.el
index d01751a..bd44932 100644
--- a/websocket.el
+++ b/websocket.el
@@ -23,6 +23,15 @@
 ;;; Commentary:
 ;; This implements RFC 6455, which can be found at
 ;; http://tools.ietf.org/html/rfc6455.
+;;
+;; Websockets are created by calling `websocket-open', which returns a
+;; `websocket' struct.  Users of this library use the websocket
+;; struct, and can call methods `websocket-send-text', which sends
+;; text over the websocket, or `websocket-send', which sends a
+;; `websocket-frame' struct, enabling finer control of what is sent.
+;; A calback is passed to `websocket-open' that will retrieve
+;; websocket frames called from the websocket.  Websockets are
+;; eventually closed with `websocket-close'.
 
 (require 'bindat)
 (require 'url-parse)

commit 9645a253bc346740c94254f149fe66f3f39b55cf
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jun 3 04:48:12 2012 +0400

    Move module pattern support to `js2-imenu-extras`

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index a85a41d..32bfce3 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -41,11 +41,23 @@ in a shared namespace."
   :type 'string
   :group 'js2-mode)
 
+(defcustom js2-imenu-show-module-pattern t
+  "Non-nil to recognize the module pattern:
+
+var foobs = (function(a) {
+  return {fib: function() {}, fub: function() {}};
+})(b);
+
+We record the returned hash as belonging to the named module, and
+prefix any functions defined inside the IIFE with the module name."
+  :type 'boolean
+  :group 'js2-mode)
+
 (defun js2-imenu-extras-setup ()
   (when js2-imenu-enabled-frameworks
     (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
-  (when js2-imenu-show-other-functions
-    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))
+  (when (or js2-imenu-show-other-functions js2-imenu-show-module-pattern)
+    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-walk-ast t)))
 
 (declare (special root))
 
@@ -104,22 +116,54 @@ in a shared namespace."
                                      (js2-compute-nested-prop-get subject)
                                      (js2-node-abs-pos methods)))))))
 
-(defun js2-imenu-record-hashes ()
+(defun js2-imenu-walk-ast ()
   (js2-visit-ast
    root
    (lambda (node end-p)
      (unless end-p
-       (if (and (js2-object-prop-node-p node)
-                (js2-function-node-p (js2-object-prop-node-right node)))
-           (let ((fn-node (js2-object-prop-node-right node)))
-             (unless (and js2-imenu-function-map
-                          (gethash fn-node js2-imenu-function-map))
-               (let ((key-node (js2-object-prop-node-left node)))
-                 (js2-record-imenu-entry fn-node
-                                         (list js2-imenu-other-functions-ns
-                                               (js2-prop-node-name key-node))
-                                         (js2-node-abs-pos key-node))))
-             nil)
-         t)))))
+       (cond
+        ((and js2-imenu-show-other-functions
+              (js2-object-prop-node-p node))
+         (js2-imenu-record-orphan-function node))
+        ((and js2-imenu-show-module-pattern
+              (js2-assign-node-p node))
+         (js2-imenu-record-module-pattern node)))
+       t))))
+
+(defun js2-imenu-record-orphan-function (node)
+  "Record orphan function when it's the value of NODE.
+NODE must be `js2-object-prop-node'."
+  (when (js2-function-node-p (js2-object-prop-node-right node))
+    (let ((fn-node (js2-object-prop-node-right node)))
+      (unless (and js2-imenu-function-map
+                   (gethash fn-node js2-imenu-function-map))
+        (let ((key-node (js2-object-prop-node-left node)))
+          (js2-record-imenu-entry fn-node
+                                  (list js2-imenu-other-functions-ns
+                                        (js2-prop-node-name key-node))
+                                  (js2-node-abs-pos key-node)))))))
+
+(defun js2-imenu-record-module-pattern (node)
+  "Recognize and record module pattern use instance.
+NODE must be `js2-assign-node'."
+  (let ((init (js2-assign-node-right node)))
+    (when (js2-call-node-p init)
+      (let ((target (js2-assign-node-left node))
+            (callt (js2-call-node-target init)))
+        ;; Just basic call form: (function() {...})();
+        ;; TODO: Handle variations without duplicating 
`js2-wrapper-function-p'?
+        (when (and (js2-paren-node-p callt)
+                   (js2-function-node-p (js2-paren-node-expr callt)))
+          (let* ((fn (js2-paren-node-expr callt))
+                 (blk (js2-function-node-body fn))
+                 (ret (car (last (js2-block-node-kids blk)))))
+            (when (and (js2-return-node-p ret)
+                       (js2-object-node-p (js2-return-node-retval ret)))
+              ;; TODO: Map function names when revealing module pattern is 
used.
+              (let ((retval (js2-return-node-retval ret)))
+                (js2-record-object-literal retval
+                                           (js2-compute-nested-prop-get target)
+                                           (js2-node-abs-pos retval)))
+              (js2-record-imenu-functions fn target))))))))
 
 (provide 'js2-imenu-extras)
diff --git a/js2-mode.el b/js2-mode.el
index f61b558..915759f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6798,7 +6798,8 @@ the parent function, look up its qname, then prepend a 
copy of it to the chain."
 (defun js2-record-imenu-functions (node &optional var)
   "Record function definitions for imenu.
 NODE is a function node or an object literal.
-VAR, if non-nil, is the expression that NODE is being assigned to."
+VAR, if non-nil, is the expression that NODE is being assigned to.
+When passed arguments of wrong type, does nothing."
   (when js2-parse-ide-mode
     (let ((fun-p (js2-function-node-p node))
           qname left fname-node pos)
@@ -6874,34 +6875,6 @@ we append the property name to QNAME, then call 
`js2-record-imenu-entry'."
                                      (append qname (list (js2-infix-node-left 
e)))
                                      (+ pos (js2-node-pos right)))))))))
 
-(defun js2-record-assign-functions (init target)
-  "Record the functions involved in the assignment for imenu.
-TARGET is the target node, INIT is the value node."
-  (cond
-   ((or (js2-object-node-p init)
-        (js2-function-node-p init))
-    (js2-record-imenu-functions init target))
-   ((js2-call-node-p init)
-    ;; Module pattern: var foobs = (function(a) {return {fib: fun...}})(b);
-    ;; We record the returned hash as belonging to the named module, and prefix
-    ;; any functions defined inside IIFE with the module name.
-    (let ((callt (js2-call-node-target init)))
-      ;; Just basic call form: (function() {...})();
-      ;; TODO: Handle variations without duplicating `js2-wrapper-function-p'?
-      (when (and (js2-paren-node-p callt)
-                 (js2-function-node-p (js2-paren-node-expr callt)))
-        (let* ((fn (js2-paren-node-expr callt))
-               (blk (js2-function-node-body fn))
-               (ret (car (last (js2-block-node-kids blk)))))
-          (when (and (js2-return-node-p ret)
-                     (js2-object-node-p (js2-return-node-retval ret)))
-            ;; TODO: Map function names when revealing module pattern is used.
-            (let ((retval (js2-return-node-retval ret)))
-              (js2-record-object-literal retval
-                                         (js2-compute-nested-prop-get target)
-                                         (js2-node-abs-pos retval)))
-            (js2-record-imenu-functions fn target))))))))
-
 (defsubst js2-node-top-level-decl-p (node)
   "Return t if NODE's name is defined in the top-level scope.
 Also returns t if NODE's name is not defined in any scope, since it implies
@@ -8520,8 +8493,7 @@ Returns the parsed `js2-var-decl-node' expression node."
       (when (js2-match-token js2-ASSIGN)
         (setq init (js2-parse-assign-expr)
               end (js2-node-end init))
-        (when js2-parse-ide-mode
-          (js2-record-assign-functions init name)))
+        (js2-record-imenu-functions init name))
       (when name
         (js2-set-face nbeg nend (if (js2-function-node-p init)
                                     'font-lock-function-name-face
@@ -8682,7 +8654,7 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
                                        :right right))
         (when js2-parse-ide-mode
           (js2-highlight-assign-targets pn left right)
-          (js2-record-assign-functions right left))
+          (js2-record-imenu-functions right left))
         ;; do this last so ide checks above can use absolute positions
         (js2-node-add-children pn left right))
       pn)))

commit 6c42988804788b1cbfd7b58ef8dc587ed67e4ee9
Author: Andrew Hyatt <address@hidden>
Date:   Sat Jun 2 20:17:51 2012 -0400

    Check for HTTP 101 response code, and if there is any failure in the
    response code on in the headers, close the connection.

diff --git a/websocket-test.el b/websocket-test.el
index 7d02baf..3ea37a6 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -108,6 +108,11 @@
 (defun websocket-test-header-with-lines (&rest lines)
   (mapconcat 'identity (append lines '("\r\n")) "\r\n"))
 
+(ert-deftest websocket-verify-response-code ()
+  (should (websocket-verify-response-code "HTTP/1.1 101"))
+  (should-error (websocket-verify-response-code "HTTP/1.1 400"))
+  (should-error (websocket-verify-response-code "HTTP/1.1 200")))
+
 (ert-deftest websocket-verify-headers ()
   (let ((accept "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
         (invalid-accept "Sec-WebSocket-Accept: bad")
@@ -312,6 +317,7 @@
            (websocket-encode-frame frame2))))
     (flet ((websocket-process-frame (websocket frame)
                                     (push frame processed-frames))
+           (websocket-verify-response-code (output) t)
            (websocket-verify-headers (websocket output) t))
       (websocket-outer-filter fake-ws "Sec-")
       (should (eq (websocket-ready-state fake-ws) 'connecting))
@@ -325,6 +331,23 @@
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
       (should (equal (list frame2 frame1) processed-frames)))))
 
+(ert-deftest websocket-outer-filter-bad-connection ()
+  (let* ((on-open-calledp)
+         (websocket-closed-calledp)
+         (fake-ws (websocket-inner-create
+                   :conn t :url t :accept-string t
+                   :on-open (lambda (websocket)
+                              (setq on-open-calledp t)))))
+    (flet ((websocket-verify-response-code (output) t)
+           (websocket-verify-headers (websocket output) (error "Bad headers!"))
+           (websocket-close (websocket) (setq websocket-closed-calledp t)))
+      (condition-case err
+          (progn (websocket-outer-filter fake-ws "HTTP/1.1 101\r\n\r\n")
+                 (error "Should have thrown an error!"))
+        (error
+         (should-not on-open-calledp)
+         (should websocket-closed-calledp))))))
+
 (defun websocket-test-get-filtered-response-with-error
   (frames &optional callback)
   (let* ((filter-frames)
diff --git a/websocket.el b/websocket.el
index 93534f2..d01751a 100644
--- a/websocket.el
+++ b/websocket.el
@@ -402,6 +402,17 @@ These are defined as in `websocket-open'."
           (insert (apply 'format (append (list msg) args)))
           (insert "\n"))))))
 
+(defun websocket-verify-response-code (output)
+  "Verify that OUTPUT contains a valid HTTP response code.
+The only acceptable one to websocket is responce code 101.
+A t value will be returned on success, and an error thrown
+if not."
+  (string-match "HTTP/1.1 \\([[:digit:]]+\\)" output)
+  (unless (equal "101" (match-string 1 output))
+       (error "Bad HTTP response code while opening websocket connection: %s"
+              (match-string 1 output)))
+  t)
+
 (defun websocket-verify-headers (websocket output)
   "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
 The output is assumed to have complete headers.  This function
@@ -469,7 +480,8 @@ If the frame is a close, we terminate the connection."
 (defun websocket-outer-filter (websocket output)
   "Filter the WEBSOCKET server's OUTPUT.
 This will parse headers and process frames repeatedly until there
-is no more output or the connection closes."
+is no more output or the connection closes.  If the websocket
+connection is invalid, the connection will be closed."
   (websocket-debug websocket "Received: %s" output)
   (let ((start-point)
         (end-point 0)
@@ -480,7 +492,13 @@ is no more output or the connection closes."
     (when (and (eq 'connecting (websocket-ready-state websocket))
                (setq header-end-pos (string-match "\r\n\r\n" text))
                (setq start-point (+ 4 header-end-pos)))
-      (websocket-verify-headers websocket text)
+      (condition-case err
+          (progn
+            (websocket-verify-response-code text)
+            (websocket-verify-headers websocket text))
+        (error
+         (websocket-close websocket)
+         (error err)))
       (setf (websocket-ready-state websocket) 'open)
       (condition-case err
           (funcall (websocket-on-open websocket) websocket)

commit 881c6cac96141eb4050efa969a2bd42c44f77aa2
Author: Andrew Hyatt <address@hidden>
Date:   Fri Jun 1 22:39:42 2012 -0400

    Implement support for specifying extensions.

diff --git a/websocket-test.el b/websocket-test.el
index b1b1338..7d02baf 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -120,7 +120,12 @@
          (websocket-inner-create
              :conn "fake-conn" :url "ws://foo/bar"
              :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
-             :protocol "myprotocol")))
+             :protocol "myprotocol"))
+        (ws-with-extensions
+         (websocket-inner-create
+             :conn "fake-conn" :url "ws://foo/bar"
+             :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+             :extensions '("ext1" "ext2"))))
     (should (websocket-verify-headers
              ws
              (websocket-test-header-with-lines accept upgrade connection)))
@@ -149,7 +154,50 @@
      (websocket-verify-headers
       ws-with-protocol
       (websocket-test-header-with-lines accept upgrade connection
-                                        "Sec-Websocket-Protocol: 
myprotocol")))))
+                                        "Sec-Websocket-Protocol: myprotocol")))
+    (should-error
+     (websocket-verify-headers
+      ws-with-extensions
+      (websocket-test-header-with-lines accept upgrade connection
+                                        "Sec-Websocket-Extensions: foo")))
+    (should
+     (websocket-verify-headers
+      ws-with-extensions
+      (websocket-test-header-with-lines
+       accept upgrade connection "Sec-Websocket-Extensions: ext1, ext2; a=1")))
+    (should (equal '("ext1" "ext2; a=1")
+                   (websocket-server-extensions ws-with-extensions)))
+    (should
+     (websocket-verify-headers
+      ws-with-extensions
+      (websocket-test-header-with-lines accept upgrade connection
+                                        "Sec-Websocket-Extensions: ext1"
+                                        "Sec-Websocket-Extensions: ext2; 
a=1")))
+    (should (equal '("ext1" "ext2; a=1")
+                   (websocket-server-extensions ws-with-extensions)))))
+
+(ert-deftest websocket-create-headers ()
+  (let ((system-name "mysystem")
+        (base-headers (concat "Host: www.example.com\r\n"
+                              "Upgrade: websocket\r\n"
+                              "Connection: Upgrade\r\n"
+                              "Sec-WebSocket-Key: key\r\n"
+                              "Origin: mysystem\r\n"
+                              "Sec-WebSocket-Version: 13\r\n")))
+    (should (equal (concat base-headers "\r\n")
+                   (websocket-create-headers "ws://www.example.com/path"
+                                             "key" nil nil)))
+    (should (equal (concat base-headers
+                           "Sec-WebSocket-Protocol: protocol\r\n\r\n")
+                   (websocket-create-headers "ws://www.example.com/path"
+                                             "key" "protocol" nil)))
+    (should (equal
+             (concat base-headers
+                     "Sec-WebSocket-Extensions: ext1; a; b=2, ext2\r\n\r\n")
+             (websocket-create-headers "ws://www.example.com/path"
+                                       "key" nil
+                                       '(("ext1" . ("a" "b=2"))
+                                         ("ext2")))))))
 
 (ert-deftest websocket-process-frame ()
   (let* ((sent)
diff --git a/websocket.el b/websocket.el
index 95fea2e..93534f2 100644
--- a/websocket.el
+++ b/websocket.el
@@ -57,6 +57,9 @@ called.
 
 `on-open', `on-message' and `on-close' are described in
 `websocket-open'.
+
+The `server-extensions' slot lists the extensions accepted by the
+server.
 "
   ;; API
   (ready-state 'connecting)
@@ -68,6 +71,8 @@ called.
   ;; Other data - clients should not have to access this.
   (url (assert nil) :read-only t)
   (protocol nil :read-only t)
+  (extensions nil :read-only t)
+  server-extensions
   (conn (assert nil) :read-only t)
   (accept-string (assert nil))
   (inflight-input nil))
@@ -256,25 +261,33 @@ the frame finishes.  If the frame is not completed, 
return NIL."
        :length payload-end
        :completep (> fin 0)))))
 
-(defun* websocket-open (url &key protocol (on-open 'identity)
+(defun* websocket-open (url &key protocol extensions (on-open 'identity)
                             (on-message 'identity) (on-close 'identity))
   "Open a websocket connection to URL, returning the `websocket' struct.
 The PROTOCOL argument is optional, and setting it will declare to
 the server that this client supports the protocol.  We will
 require that the server also has to support that protocol.
+
+Similar logic applies to EXTENSIONS, which is a list of conses,
+the car of which is a string naming the extension, and the cdr of
+which is the list of parameter strings to use for that extension.
+The parameter strings are of the form \"key=value\" or \"value\".
+EXTENSIONS can be NIL if none are in use.  An example value would
+be '(\"deflate-stream\" . (\"mux\" \"max-channels=4\")).
+
 Optionally you can specify
-:on-open, :on-message and :on-close callbacks as well.
+ON_OPEN, ON-MESSAGE and ON-CLOSE callbacks as well.
 
-The on-open callback is called after the connection is
+The ON-OPEN callback is called after the connection is
 established with the websocket as the only argument.  The return
 value is unused.
 
-The on-message callback is called after receiving a frame, and is
+The ON-MESSAGE callback is called after receiving a frame, and is
 called with the websocket as the first argument and
 `websocket-frame' struct as the second.  The return value is
 unused.
 
-The on-close callback is called after the connection is closed, or
+The ON-CLOSE callback is called after the connection is closed, or
 failed to open.  It is called with the websocket as the only
 argument, and the return value is unused.
 
@@ -308,6 +321,7 @@ variable `websocket-debug' to t."
                      :on-message on-message
                      :on-close on-close
                      :protocol protocol
+                     :extensions (mapcar 'car extensions)
                      :accept-string
                      (websocket-calculate-accept key))))
     (process-put conn :websocket websocket)
@@ -335,24 +349,37 @@ variable `websocket-debug' to t."
                                    (if (> (length path) 0) path "/"))))
     (websocket-debug websocket "Sending handshake, key: %s, acceptance: %s"
                      key (websocket-accept-string websocket))
-    (process-send-string
-     conn
-     (format (concat "Host: %s\r\n"
-                     "Upgrade: websocket\r\n"
-                     "Connection: Upgrade\r\n"
-                     "Sec-WebSocket-Key: %s\r\n"
-                     "Origin: %s\r\n"
-                     "Sec-WebSocket-Version: 13\r\n"
-                     (when protocol
-                       "Sec-WebSocket-Protocol: %s\r\n")
-                     "\r\n")
-             (url-host (url-generic-parse-url url))
-             key
-             system-name
-             protocol))
+    (process-send-string conn
+                         (websocket-create-headers url key protocol 
extensions))
     (websocket-debug websocket "Websocket opened")
     websocket))
 
+(defun websocket-create-headers (url key protocol extensions)
+  "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS.
+These are defined as in `websocket-open'."
+  (format (concat "Host: %s\r\n"
+                  "Upgrade: websocket\r\n"
+                  "Connection: Upgrade\r\n"
+                  "Sec-WebSocket-Key: %s\r\n"
+                  "Origin: %s\r\n"
+                  "Sec-WebSocket-Version: 13\r\n"
+                  (when protocol
+                    "Sec-WebSocket-Protocol: %s\r\n")
+                  (when extensions
+                    (format "Sec-WebSocket-Extensions: %s\r\n"
+                            (mapconcat
+                             (lambda (ext)
+                               (concat (car ext)
+                                       (when (cdr ext) "; ")
+                                       (when (cdr ext)
+                                         (mapconcat 'identity (cdr ext) "; 
"))))
+                             extensions ", ")))
+                  "\r\n")
+          (url-host (url-generic-parse-url url))
+          key
+          system-name
+          protocol))
+
 (defun websocket-get-debug-buffer-create (websocket)
   "Get or create the buffer corresponding to WEBSOCKET."
   (get-buffer-create (format " *websocket %s debug*"
@@ -378,7 +405,8 @@ variable `websocket-debug' to t."
 (defun websocket-verify-headers (websocket output)
   "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
 The output is assumed to have complete headers.  This function
-will either return t or call `error'."
+will either return t or call `error'.  This has the side-effect
+of populating the list of server extensions to WEBSOCKET."
   (websocket-debug websocket "Checking headers: %s" output)
   (let ((accept-string
          (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
@@ -399,7 +427,24 @@ will either return t or call `error'."
       (unless (string-match
                (format "\r\nSec-Websocket-Protocol: %s\r\n"
                        (websocket-protocol websocket)) output)
-        (error "Incorrect or missing protocol returned by the server."))))
+        (error "Incorrect or missing protocol returned by the server.")))
+    (let ((pos 0)
+          (extensions))
+      (while (and pos
+                  (string-match "\r\nSec-Websocket-Extensions: \\(.*\\)\r\n"
+                      output pos))
+        (when (setq pos (match-end 1))
+          (setq extensions (append extensions (split-string
+                                               (match-string 1 output) ", 
?")))))
+      (let ((extra-extensions
+             (set-difference (mapcar (lambda (ext) (first (split-string ext "; 
?")))
+                                     extensions)
+                             (websocket-extensions websocket)
+                             :test 'equal)))
+        (when extra-extensions
+          (error "Non-requested extensions returned by server: %s"
+                 extra-extensions)))
+      (setf (websocket-server-extensions websocket) extensions)))
   ;; return true
   t)
 

commit fb26aa742850bc005f2cbacd5b53fb1e5a007dec
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 31 23:47:32 2012 -0400

    Make the API more like W3C's API.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 3836dfe..ff98153 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -17,14 +17,15 @@
 (defvar wstest-msgs nil)
 (defvar wstest-closed nil)
 
-(setq websocket-require-server-accept t)
+(message "Opening the websocket")
 
 (defvar wstest-ws
   (websocket-open
    "ws://127.0.0.1:9999"
-   (lambda (frame) (push (websocket-frame-payload frame) wstest-msgs)
-     (message "ws frame: %S" (websocket-frame-payload frame)))
-   (lambda () (setq wstest-closed t))))
+   :on-message (lambda (websocket frame)
+                 (push (websocket-frame-payload frame) wstest-msgs)
+                 (message "ws frame: %S" (websocket-frame-payload frame)))
+   :on-close (lambda (websocket) (setq wstest-closed t))))
 
 (defun wstest-pop-to-debug ()
   "Open websocket log buffer. Not used in testing. Just for debugging."
diff --git a/websocket-test.el b/websocket-test.el
index 4827d44..b1b1338 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -105,33 +105,63 @@
                  (substring websocket-test-masked-hello 0
                             (- (length websocket-test-masked-hello) (+ i 
1)))))))
 
-(defun websocket-test-make-websocket-with-accept-string (s)
-  (make-websocket :conn "fake-conn" :url "ws://foo/bar" :filter t
-                  :close-callback t :accept-string s))
+(defun websocket-test-header-with-lines (&rest lines)
+  (mapconcat 'identity (append lines '("\r\n")) "\r\n"))
 
-(ert-deftest websocket-verify-handshake ()
-  ;; This examples comes from the RFC
-  (should (websocket-verify-handshake
-           (websocket-test-make-websocket-with-accept-string
-            "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
-           "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"))
-  (should-error (websocket-verify-handshake
-                 (websocket-test-make-websocket-with-accept-string
-                  "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
-                 "Sec-WebSocket-Accept: foo\r\n")))
+(ert-deftest websocket-verify-headers ()
+  (let ((accept "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+        (invalid-accept "Sec-WebSocket-Accept: bad")
+        (upgrade "Upgrade: websocket")
+        (connection "Connection: upgrade")
+        (ws (websocket-inner-create
+             :conn "fake-conn" :url "ws://foo/bar"
+             :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="))
+        (ws-with-protocol
+         (websocket-inner-create
+             :conn "fake-conn" :url "ws://foo/bar"
+             :accept-string "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+             :protocol "myprotocol")))
+    (should (websocket-verify-headers
+             ws
+             (websocket-test-header-with-lines accept upgrade connection)))
+    (should-error
+     (websocket-verify-headers
+      ws
+      (websocket-test-header-with-lines invalid-accept upgrade connection)))
+    (should-error (websocket-verify-headers
+                   ws
+                   (websocket-test-header-with-lines upgrade connection)))
+    (should-error (websocket-verify-headers
+                   ws
+                   (websocket-test-header-with-lines accept connection)))
+    (should-error (websocket-verify-headers
+                   ws
+                   (websocket-test-header-with-lines accept upgrade)))
+    (should-error (websocket-verify-headers
+                   ws-with-protocol
+                   (websocket-test-header-with-lines accept upgrade 
connection)))
+    (should-error
+     (websocket-verify-headers
+      ws-with-protocol
+      (websocket-test-header-with-lines accept upgrade connection
+                                        "Sec-Websocket-Protocol: foo")))
+    (should
+     (websocket-verify-headers
+      ws-with-protocol
+      (websocket-test-header-with-lines accept upgrade connection
+                                        "Sec-Websocket-Protocol: 
myprotocol")))))
 
 (ert-deftest websocket-process-frame ()
   (let* ((sent)
          (processed)
          (deleted)
-         (websocket (make-websocket :conn "fake-conn"
-                                    :url "ws://foo/bar"
-                                    :filter (lambda (frame)
-                                              (setq
-                                               processed
-                                               (websocket-frame-payload 
frame)))
-                                    :close-callback t
-                                    :accept-string "accept-string")))
+         (websocket (websocket-inner-create
+                     :conn t :url t
+                     :on-message (lambda (websocket frame)
+                                   (setq
+                                    processed
+                                    (websocket-frame-payload frame)))
+                     :accept-string t)))
     (dolist (opcode '(text binary continuation))
       (setq processed nil)
       (should (equal
@@ -206,19 +236,22 @@
            (websocket-openp (websocket) t)
            (kill-buffer (buffer))
            (process-buffer (conn)))
-      (websocket-close (make-websocket :conn "fake-conn"
-                                       :filter t
-                                       :url t
-                                       :accept-string t
-                                       :close-callback t))
+      (websocket-close (websocket-inner-create
+                        :conn "fake-conn"
+                        :url t
+                        :accept-string t))
       (should (equal sent-frames (list
                                   (make-websocket-frame :opcode 'close
                                                         :completep t)))))))
 
 (ert-deftest websocket-outer-filter ()
-  (let* ((fake-ws (make-websocket :conn t :filter t :url t
-                                  :accept-string t :close-callback t
-                                  :open-callback (lambda () (setq 
open-callback-called t))))
+  (let* ((fake-ws (websocket-inner-create
+                   :conn t :url t :accept-string t
+                   :on-open (lambda (websocket)
+                              (should (eq (websocket-ready-state websocket)
+                                          'open))
+                              (setq open-callback-called t)
+                              (error "Ignore me!"))))
          (processed-frames)
          (frame1 (make-websocket-frame :opcode 'text :payload "foo" :completep 
t
                                        :length 9))
@@ -231,8 +264,9 @@
            (websocket-encode-frame frame2))))
     (flet ((websocket-process-frame (websocket frame)
                                     (push frame processed-frames))
-           (websocket-verify-handshake (websocket output) t))
+           (websocket-verify-headers (websocket output) t))
       (websocket-outer-filter fake-ws "Sec-")
+      (should (eq (websocket-ready-state fake-ws) 'connecting))
       (should-not open-callback-called)
       (websocket-outer-filter fake-ws "WebSocket-Accept: acceptstring")
       (should-not open-callback-called)
@@ -240,7 +274,6 @@
                                        "\r\n\r\n"
                                        (substring websocket-frames 0 2)))
       (should open-callback-called)
-      (should (websocket-header-read-p fake-ws))
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
       (should (equal (list frame2 frame1) processed-frames)))))
 
@@ -248,13 +281,13 @@
   (frames &optional callback)
   (let* ((filter-frames)
          (websocket
-          (make-websocket :conn "fake-conn"
-                          :filter (lambda (frame)
-                                    (push frame filter-frames)
-                                    (when callback (funcall callback)))
-                          :close-callback (lambda (not-called) (assert nil))
-                          :url "ws://foo/bar"
-                          :accept-string t))
+          (websocket-inner-create
+           :conn "fake-conn"
+           :on-message (lambda (websocket frame)
+                         (push frame filter-frames)
+                         (when callback (funcall callback)))
+           :on-close (lambda (not-called) (assert nil))
+           :url t :accept-string t))
          err-list)
     (dolist (frame frames)
       (condition-case err
@@ -295,8 +328,7 @@
     (should (equal err-list nil)))))
 
 (ert-deftest websocket-send ()
-  (let ((ws (make-websocket :conn t :url t :filter t :close-callback t
-                            :accept-string t)))
+  (let ((ws (websocket-inner-create :conn t :url t :accept-string t)))
     (flet ((websocket-ensure-connected (websocket))
            (websocket-openp (websocket) t)
            (process-send-string (conn string)))
diff --git a/websocket.el b/websocket.el
index 11aafb9..95fea2e 100644
--- a/websocket.el
+++ b/websocket.el
@@ -30,16 +30,47 @@
 (eval-when-compile (require 'cl))
 
 ;;; Code:
-(defstruct websocket
-  (conn (assert nil) :read-only t)
-  (filter (assert nil) :read-only t)
-  (close-callback (assert nil) :read-only t)
-  (open-callback nil :read-only t)
+(defstruct (websocket
+            (:constructor nil)
+            (:constructor websocket-inner-create))
+  "A websocket structure.
+This follows the W3C Websocket API, except translated to elisp
+idioms.  The API is implemented in both the websocket struct and
+additional methods.  Due to how defstruct slots are accessed, all
+API methods are prefixed with \"websocket-\" and take a websocket
+as an argument, so the distrinction between the struct API and
+the additional helper APIs are not visible to the caller.
+
+The websocket is created with `websocket-open', which takes a
+url, an optional protocol string, and optional handlers, and
+returns a websocket.  If the protocol is specified, the client
+must support that protocol or the websocket connection will fail.
+
+`ready-state' contains one of 'connecting, 'open, or
+'closed, depending on the state of the websocket.
+
+The W3C API \"bufferedAmount\" call is not currently implemented,
+since there is no elisp API to get the buffered amount from the
+subprocess.  There may, in fact, be output data buffered,
+however, when the `on-message' or `close-callback' callbacks are
+called.
+
+`on-open', `on-message' and `on-close' are described in
+`websocket-open'.
+"
+  ;; API
+  (ready-state 'connecting)
+  client-data
+  on-open
+  on-message
+  on-close
+
+  ;; Other data - clients should not have to access this.
   (url (assert nil) :read-only t)
+  (protocol nil :read-only t)
+  (conn (assert nil) :read-only t)
   (accept-string (assert nil))
-  (handshake-accept-passed-p nil)
-  (header-read-p nil)
-  (inflight-packet nil))
+  (inflight-input nil))
 
 (defvar websocket-debug nil
   "Set to true to output debugging info to a per-websocket buffer.
@@ -53,11 +84,6 @@ URL of the connection.")
   "The websocket GUID as defined in RFC 6455.
 Do not change unless the RFC changes.")
 
-(defvar websocket-require-server-accept t
-  "If true, we check the Sec-WebSocket-Accept header.
-This is required by the RFC as part of the connection
-handshake.")
-
 (defvar websocket-mask-frames t
   "If true, we mask frames as defined in the spec.
 This is recommended to be true, and some servers will refuse to
@@ -230,15 +256,36 @@ the frame finishes.  If the frame is not completed, 
return NIL."
        :length payload-end
        :completep (> fin 0)))))
 
-(defun websocket-open (url filter &optional close-callback)
-  "Open a websocket connection to URL.
-`websocket-frame' structs are sent as the only argument to
-FILTER, and if the connection is closed, then CLOSE-CALLBACK is
-called.  Errors from FILTER function will be ignored.  You should
-catch it in the FILTER function in order to recover from the
-error.  Errors will be messaged using `messsage' function.  To
-suppress messaging errors, set `websocket-ignore-error' to t.
-You can log errors by setting variable `websocket-debug' to t."
+(defun* websocket-open (url &key protocol (on-open 'identity)
+                            (on-message 'identity) (on-close 'identity))
+  "Open a websocket connection to URL, returning the `websocket' struct.
+The PROTOCOL argument is optional, and setting it will declare to
+the server that this client supports the protocol.  We will
+require that the server also has to support that protocol.
+Optionally you can specify
+:on-open, :on-message and :on-close callbacks as well.
+
+The on-open callback is called after the connection is
+established with the websocket as the only argument.  The return
+value is unused.
+
+The on-message callback is called after receiving a frame, and is
+called with the websocket as the first argument and
+`websocket-frame' struct as the second.  The return value is
+unused.
+
+The on-close callback is called after the connection is closed, or
+failed to open.  It is called with the websocket as the only
+argument, and the return value is unused.
+
+For each of these event handlers, the client code can store
+arbitrary data in the `client-data' slot in the returned
+websocket. Errors from the callbacks will be ignored.  You should
+catch it in the callback function in order to recover from the
+error.  Errors not caught will be messaged using `messsage'
+function.  To suppress messaging errors, set
+`websocket-ignore-error' to t.  You can log errors by setting
+variable `websocket-debug' to t."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key (websocket-genkey))
@@ -254,22 +301,33 @@ You can log errors by setting variable `websocket-debug' 
to t."
                  (if (equal (url-type url-struct) "wss")
                      (error "Not implemented yet")
                    (error "Unknown protocol"))))
-         (websocket (make-websocket :conn conn :url url :filter filter
-                                    :close-callback close-callback
-                                    :accept-string
-                                    (websocket-calculate-accept key))))
-    (lexical-let ((websocket websocket))
-      (set-process-filter conn
-                          (lambda (process output)
-                            (websocket-outer-filter websocket output)))
-      (when close-callback
-        (set-process-sentinel conn
-                              (lambda (process change)
-                                (websocket-debug websocket
-                                                 "State change to %s" change)
-                                (unless (websocket-openp websocket)
-                                  (funcall (websocket-close-callback
-                                            websocket)))))))
+         (websocket (websocket-inner-create
+                     :conn conn
+                     :url url
+                     :on-open on-open
+                     :on-message on-message
+                     :on-close on-close
+                     :protocol protocol
+                     :accept-string
+                     (websocket-calculate-accept key))))
+    (process-put conn :websocket websocket)
+    (set-process-filter conn
+                        (lambda (process output)
+                          (let ((websocket (process-get process :websocket)))
+                            (websocket-outer-filter websocket output))))
+    (set-process-sentinel
+     conn
+     (lambda (process change)
+       (let ((websocket (process-get process :websocket)))
+         (websocket-debug websocket
+                          "State change to %s" change))
+       (unless (eq 'closed (websocket-ready-state websocket))
+         (condition-case err
+             (funcall (websocket-on-close websocket)
+                      websocket)
+           (error (websocket-error
+                   websocket
+                   "Got error from the op-close function: %s"))))))
     (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"
@@ -285,10 +343,13 @@ You can log errors by setting variable `websocket-debug' 
to t."
                      "Sec-WebSocket-Key: %s\r\n"
                      "Origin: %s\r\n"
                      "Sec-WebSocket-Version: 13\r\n"
+                     (when protocol
+                       "Sec-WebSocket-Protocol: %s\r\n")
                      "\r\n")
              (url-host (url-generic-parse-url url))
              key
-             system-name))
+             system-name
+             protocol))
     (websocket-debug websocket "Websocket opened")
     websocket))
 
@@ -297,11 +358,11 @@ You can log errors by setting variable `websocket-debug' 
to t."
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
 
-(defun websocket-error (msg &rest args)
+(defun websocket-error (websocket msg &rest args)
   "Report error message MSG."
   (unless websocket-ignore-error
     (apply 'message msg args))
-  (apply 'websocket-debug msg args))
+  (apply 'websocket-debug websocket msg args))
 
 (defun websocket-debug (websocket msg &rest args)
   "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
@@ -314,20 +375,33 @@ You can log errors by setting variable `websocket-debug' 
to t."
           (insert (apply 'format (append (list msg) args)))
           (insert "\n"))))))
 
-(defun websocket-verify-handshake (websocket output)
-  "Based on WEBSOCKET's key, verify that OUTPUT contains a valid handshake.
+(defun websocket-verify-headers (websocket output)
+  "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid.
 The output is assumed to have complete headers.  This function
 will either return t or call `error'."
+  (websocket-debug websocket "Checking headers: %s" output)
   (let ((accept-string
          (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
-    (websocket-debug websocket "Handshake received, checking for: %s" 
accept-string)
-    (if (string-match (regexp-quote accept-string) output)
-        (progn
-          (setf (websocket-handshake-accept-passed-p websocket) t)
-          (websocket-debug websocket "Handshake accepted")
-          ;; return true
-          t)
-      (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
+    (websocket-debug websocket "Checking for accept header: %s" accept-string)
+    (unless (string-match (regexp-quote accept-string) output)
+      (error "Incorrect handshake from websocket: is this really a websocket 
connection?")))
+  (let ((case-fold-search t))
+    (websocket-debug websocket "Checking for upgrade header")
+    (unless (string-match "\r\nUpgrade: websocket\r\n" output)
+      (error "No 'Upgrade: websocket' header found."))
+    (websocket-debug websocket "Checking for connection header")
+    (unless (string-match "\r\nConnection: upgrade\r\n" output)
+      (error "No 'Connection: upgrade' header found"))
+    ;; TODO(ahyatt) Implement checking for extensions
+    (when (websocket-protocol websocket)
+      (websocket-debug websocket "Checking for protocol match: %s"
+                       (websocket-protocol websocket))
+      (unless (string-match
+               (format "\r\nSec-Websocket-Protocol: %s\r\n"
+                       (websocket-protocol websocket)) output)
+        (error "Incorrect or missing protocol returned by the server."))))
+  ;; return true
+  t)
 
 (defun websocket-process-frame (websocket frame)
   "Using the WEBSOCKET's filter and connection, process the FRAME.
@@ -337,8 +411,9 @@ If the frame is a close, we terminate the connection."
   (let ((opcode (websocket-frame-opcode frame)))
     (cond ((memq opcode '(continuation text binary))
            (condition-case err
-               (funcall (websocket-filter websocket) frame)
-             (error (websocket-error "Got error from the filter function: %s"
+               (funcall (websocket-on-message websocket) websocket frame)
+             (error (websocket-error websocket
+                                     "Got error from the on-message function: 
%s"
                                      (error-message-string err)))))
           ((eq opcode 'ping)
            (websocket-send websocket
@@ -353,29 +428,29 @@ is no more output or the connection closes."
   (websocket-debug websocket "Received: %s" output)
   (let ((start-point)
         (end-point 0)
-        (text (concat (websocket-inflight-packet websocket) output))
+        (text (concat (websocket-inflight-input websocket) output))
         (header-end-pos))
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
-    (when (and (not (websocket-header-read-p websocket))
+    (when (and (eq 'connecting (websocket-ready-state websocket))
                (setq header-end-pos (string-match "\r\n\r\n" text))
                (setq start-point (+ 4 header-end-pos)))
-      (setf (websocket-header-read-p websocket) t)
-      (when (and websocket-require-server-accept
-                (not (websocket-handshake-accept-passed-p websocket))
-                start-point)
-       (websocket-verify-handshake websocket text))
-      (when (websocket-open-callback websocket)
-        (funcall (websocket-open-callback websocket))))
-    (when (websocket-header-read-p websocket)
+      (websocket-verify-headers websocket text)
+      (setf (websocket-ready-state websocket) 'open)
+      (condition-case err
+          (funcall (websocket-on-open websocket) websocket)
+        (error (websocket-error websocket
+                                "Got error from the on-open function: %s"
+                                (error-message-string err)))))
+    (when (eq 'open (websocket-ready-state websocket))
       (unless start-point (setq start-point 0))
       (let ((current-frame))
         (while (and (setq current-frame (websocket-read-frame
                                          (substring text start-point))))
           (websocket-process-frame websocket current-frame)
           (incf start-point (websocket-frame-length current-frame)))))
-    ;; TODO(ahyatt) Rename websocket-inflight-packet (it isn't a packet)
-    (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
+    (setf (websocket-inflight-input websocket)
+        (substring text (or start-point 0)))))
 
 (defun websocket-send-text (websocket text)
   "To the WEBSOCKET, send TEXT as a complete frame."
@@ -404,8 +479,11 @@ This will raise an error if the frame is illegal."
                        (websocket-encode-frame frame)))
 
 (defun websocket-openp (websocket)
-  "Check WEBSOCKET and return non-nil if it is open and connected."
-  (and websocket (eq 'open (process-status (websocket-conn websocket)))))
+  "Check WEBSOCKET and return non-nil if it is open, and either
+connecting or open."
+  (and websocket
+       (not (eq 'close (websocket-ready-state websocket)))
+       (eq 'open (process-status (websocket-conn websocket)))))
 
 (defun websocket-close (websocket)
   "Close WEBSOCKET and erase all the old websocket data."
@@ -413,7 +491,10 @@ This will raise an error if the frame is illegal."
   (when (websocket-openp websocket)
     (websocket-send websocket
                     (make-websocket-frame :opcode 'close
-                                          :completep t)))
+                                          :completep t))
+    (setf (websocket-ready-state websocket) 'closed))
+  ;; Do we want to kill this?  It may result in on-closed not being
+  ;; called.
   (kill-buffer (process-buffer (websocket-conn websocket))))
 
 (defun websocket-ensure-connected (websocket)

commit 078fbf31db64329fd22428e5c185cd6e4448383d
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 29 23:53:38 2012 -0400

    Implemented onopen callback.  Soon to be renamed.

diff --git a/websocket-test.el b/websocket-test.el
index e307a32..4827d44 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -217,12 +217,14 @@
 
 (ert-deftest websocket-outer-filter ()
   (let* ((fake-ws (make-websocket :conn t :filter t :url t
-                                  :accept-string t :close-callback t))
+                                  :accept-string t :close-callback t
+                                  :open-callback (lambda () (setq 
open-callback-called t))))
          (processed-frames)
          (frame1 (make-websocket-frame :opcode 'text :payload "foo" :completep 
t
                                        :length 9))
          (frame2 (make-websocket-frame :opcode 'text :payload "bar" :completep 
t
                                        :length 9))
+         (open-callback-called)
          (websocket-frames
           (concat
            (websocket-encode-frame frame1)
@@ -231,10 +233,13 @@
                                     (push frame processed-frames))
            (websocket-verify-handshake (websocket output) t))
       (websocket-outer-filter fake-ws "Sec-")
+      (should-not open-callback-called)
       (websocket-outer-filter fake-ws "WebSocket-Accept: acceptstring")
+      (should-not open-callback-called)
       (websocket-outer-filter fake-ws (concat
                                        "\r\n\r\n"
                                        (substring websocket-frames 0 2)))
+      (should open-callback-called)
       (should (websocket-header-read-p fake-ws))
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
       (should (equal (list frame2 frame1) processed-frames)))))
diff --git a/websocket.el b/websocket.el
index 146944d..11aafb9 100644
--- a/websocket.el
+++ b/websocket.el
@@ -34,6 +34,7 @@
   (conn (assert nil) :read-only t)
   (filter (assert nil) :read-only t)
   (close-callback (assert nil) :read-only t)
+  (open-callback nil :read-only t)
   (url (assert nil) :read-only t)
   (accept-string (assert nil))
   (handshake-accept-passed-p nil)
@@ -363,7 +364,9 @@ is no more output or the connection closes."
       (when (and websocket-require-server-accept
                 (not (websocket-handshake-accept-passed-p websocket))
                 start-point)
-       (websocket-verify-handshake websocket text)))
+       (websocket-verify-handshake websocket text))
+      (when (websocket-open-callback websocket)
+        (funcall (websocket-open-callback websocket))))
     (when (websocket-header-read-p websocket)
       (unless start-point (setq start-point 0))
       (let ((current-frame))

commit d2e427207aefd210b5b16905ecb17fc77192f483
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 26 22:49:41 2012 -0400

    Check frame validity, and test it as part of websocket-send

diff --git a/websocket-test.el b/websocket-test.el
index bc5ae0c..e307a32 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -289,3 +289,21 @@
     (should (equal filter-frames (list foo-frame bar-frame)))
     (should (equal err-list nil)))))
 
+(ert-deftest websocket-send ()
+  (let ((ws (make-websocket :conn t :url t :filter t :close-callback t
+                            :accept-string t)))
+    (flet ((websocket-ensure-connected (websocket))
+           (websocket-openp (websocket) t)
+           (process-send-string (conn string)))
+      ;; Just make sure there is no error.
+      (websocket-send ws (make-websocket-frame :opcode 'ping
+                                                       :completep t)))
+    (should-error (websocket-send ws
+                                  (make-websocket-frame :opcode 'text )))
+    (should-error (websocket-send ws
+                                  (make-websocket-frame :opcode 'close
+                                                        :payload "bye!"
+                                                        :completep t)))
+    (should-error (websocket-send ws
+                                  (make-websocket-frame :opcode :close)))))
+
diff --git a/websocket.el b/websocket.el
index f894d9a..146944d 100644
--- a/websocket.el
+++ b/websocket.el
@@ -379,8 +379,18 @@ is no more output or the connection closes."
   (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
                                                   :completep t)))
 
+(defun websocket-check (frame)
+  "Check FRAME for correctness, returning true if correct."
+  (and (equal (not (memq (websocket-frame-opcode frame)
+                         '(continuation text binary)))
+              (and (not (websocket-frame-payload frame))
+                   (websocket-frame-completep frame)))))
+
 (defun websocket-send (websocket frame)
-  "To the WEBSOCKET server, send the FRAME."
+  "To the WEBSOCKET server, send the FRAME.
+This will raise an error if the frame is illegal."
+  (unless (websocket-check frame)
+    (error "Cannot send illegal frame to websocket"))
   (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
                    (websocket-frame-opcode frame)
                    (websocket-frame-payload frame))

commit 0f921694700e8e78feec16ca1c481e2afb26bfd5
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 26 21:40:52 2012 -0400

    Fix misplaced parenthesis

diff --git a/websocket.el b/websocket.el
index d481c8f..f894d9a 100644
--- a/websocket.el
+++ b/websocket.el
@@ -225,8 +225,7 @@ the frame finishes.  If the frame is not completed, return 
NIL."
            (let ((masking-key (substring s (+ 1 (cdr payload-len))
                                          (+ 5 (cdr payload-len)))))
              (websocket-mask masking-key unmasked-payload))
-         unmasked-payload
-         )
+         unmasked-payload)
        :length payload-end
        :completep (> fin 0)))))
 

commit a5f1895b069615093ca119114cf9257667497640
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 26 21:25:46 2012 -0400

    Re-apply the error handling, removed by accident during the merge.

diff --git a/websocket-test.el b/websocket-test.el
index ed05b75..bc5ae0c 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -28,30 +28,6 @@
 (require 'websocket)
 (eval-when-compile (require 'cl))
 
-(defun websocket-test-get-filtered-response-with-error
-  (outputs &optional callback)
-  (let* ((packet-data nil)
-         (websocket
-          (make-websocket :conn "fake-conn"
-                          :filter (lambda (packet)
-                                    (push packet packet-data)
-                                    (when callback (funcall callback)))
-                          :close-callback (lambda (not-called) (assert nil))
-                          :url "ws://foo/bar")))
-         err-list)
-    (dolist (output outputs)
-      (condition-case err
-          (websocket-outer-filter websocket output)
-        (error (push err err-list))))
-    (list (nreverse packet-data) (nreverse err-list)))
-
-(defun websocket-test-get-filtered-response (outputs)
-  (destructuring-bind (packet-data err-list)
-      (websocket-test-get-filtered-response-with-error outputs)
-    (assert (eq (length err-list) 0))
-    packet-data))
-
-
 (ert-deftest websocket-genbytes-length ()
   (loop repeat 100
         do (should (= (string-bytes (websocket-genbytes 16)) 16))))
@@ -262,3 +238,54 @@
       (should (websocket-header-read-p fake-ws))
       (websocket-outer-filter fake-ws (substring websocket-frames 2))
       (should (equal (list frame2 frame1) processed-frames)))))
+
+(defun websocket-test-get-filtered-response-with-error
+  (frames &optional callback)
+  (let* ((filter-frames)
+         (websocket
+          (make-websocket :conn "fake-conn"
+                          :filter (lambda (frame)
+                                    (push frame filter-frames)
+                                    (when callback (funcall callback)))
+                          :close-callback (lambda (not-called) (assert nil))
+                          :url "ws://foo/bar"
+                          :accept-string t))
+         err-list)
+    (dolist (frame frames)
+      (condition-case err
+          (websocket-process-frame websocket frame)
+        (error (push err err-list))))
+    (list (nreverse filter-frames) (nreverse err-list))))
+
+(defun websocket-test-get-filtered-response (frames)
+  (destructuring-bind (filter-frames err-list)
+      (websocket-test-get-filtered-response-with-error frames)
+    (assert (eq (length err-list) 0))
+    filter-frames))
+
+(ert-deftest websocket-filter-handle-error-in-filter ()
+  (let ((foo-frame (make-websocket-frame :opcode 'text
+                                   :payload "foo"
+                                   :completep t))
+        (bar-frame (make-websocket-frame :opcode 'text
+                                         :payload "bar"
+                                         :completep t)))
+    (destructuring-bind (filter-frames err-list)
+        (websocket-test-get-filtered-response-with-error
+         (list foo-frame bar-frame)
+         (lambda () (error "See if websocket can handle this")))
+      (should (equal filter-frames (list foo-frame bar-frame)))
+      (should (equal err-list nil)))
+    (destructuring-bind (filter-frames err-list)
+      (websocket-test-get-filtered-response-with-error
+       (list foo-frame bar-frame)
+       (lambda () "Raise another type of error" (/ 1 0)))
+    (should (equal filter-frames (list foo-frame bar-frame)))
+    (should (equal err-list nil)))
+    (destructuring-bind (filter-frames err-list)
+      (websocket-test-get-filtered-response-with-error
+       (list foo-frame bar-frame)
+       (lambda () (error "See if websocket can handle this")))
+    (should (equal filter-frames (list foo-frame bar-frame)))
+    (should (equal err-list nil)))))
+
diff --git a/websocket.el b/websocket.el
index 4938653..d481c8f 100644
--- a/websocket.el
+++ b/websocket.el
@@ -297,7 +297,7 @@ You can log errors by setting variable `websocket-debug' to 
t."
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
 
-(defun websocket-error (websocket msg &rest args)
+(defun websocket-error (msg &rest args)
   "Report error message MSG."
   (unless websocket-ignore-error
     (apply 'message msg args))
@@ -336,7 +336,10 @@ slot of WEBSOCKET.  If the frame is a ping, we reply with 
a pong.
 If the frame is a close, we terminate the connection."
   (let ((opcode (websocket-frame-opcode frame)))
     (cond ((memq opcode '(continuation text binary))
-           (funcall (websocket-filter websocket) frame))
+           (condition-case err
+               (funcall (websocket-filter websocket) frame)
+             (error (websocket-error "Got error from the filter function: %s"
+                                     (error-message-string err)))))
           ((eq opcode 'ping)
            (websocket-send websocket
                            (make-websocket-frame :opcode 'pong :completep t)))

commit 43687bd20dd04e502d170d9d679fe056bc353e89
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 26 20:27:37 2012 -0400

    Fix up doc strings.

diff --git a/websocket.el b/websocket.el
index ad4c1c3..4938653 100644
--- a/websocket.el
+++ b/websocket.el
@@ -49,16 +49,17 @@ URL of the connection.")
   "Set to true to suppress error messages.")
 
 (defconst websocket-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-  "The websocket GUID as defined in RFC 6455. Do not change
-  unless the RFC changes.")
+  "The websocket GUID as defined in RFC 6455.
+Do not change unless the RFC changes.")
 
 (defvar websocket-require-server-accept t
-  "If true, we require the correct Sec-WebSocket-Accept header
-as part of the connection handshake.")
+  "If true, we check the Sec-WebSocket-Accept header.
+This is required by the RFC as part of the connection
+handshake.")
 
 (defvar websocket-mask-frames t
-  "If true, we mask frames as defined in the spec.  This is
-recommended to be true, and some servers will refuse to
+  "If true, we mask frames as defined in the spec.
+This is recommended to be true, and some servers will refuse to
 communicate with unmasked clients.")
 
 (defun websocket-genbytes (nbytes)
@@ -121,8 +122,7 @@ NBYTES much be a power of 2, up to 8."
      `((:val . ,val)))))
 
 (defun websocket-get-opcode (s)
-  "Retrieve the opcode from the dword at the start of the frame
-given by string."
+  "Retrieve the opcode from first byte of string S."
   (websocket-ensure-length s 1)
   (let ((opcode (logand #xf (websocket-get-bytes s 1))))
     (cond ((= opcode 0) 'continuation)
@@ -133,7 +133,7 @@ given by string."
           ((= opcode 10) 'pong))))
 
 (defun websocket-get-payload-len (s)
-  "Parses out the payload length from the string.
+  "Parse out the payload length from the string S.
 We start at position 0, and return a cons of the payload length and how
 many bytes were consumed from the string."
   (websocket-ensure-length s 1)
@@ -149,7 +149,7 @@ many bytes were consumed from the string."
 (defstruct websocket-frame opcode payload length completep)
 
 (defun websocket-mask (key data)
-  "Mask string DATA with string KEY according to the RFC.
+  "Using string KEY, mask string DATA according to the RFC.
 This is used to both mask and unmask data."
   (apply
    'string
@@ -186,7 +186,7 @@ Otherwise we throw the error `websocket-incomplete-frame'."
                        (cond ((< (length payload) 126) (length payload))
                              ((< (length payload) 65536) 126)
                              (t 127)))))
-                   (when (and payloadp (>= (length payload) 126)) 
+                   (when (and payloadp (>= (length payload) 126))
                      (append (websocket-to-bytes (length payload)
                                           (cond ((< (length payload) 126) 1)
                                                 ((< (length payload) 65536) 2)
@@ -200,8 +200,8 @@ Otherwise we throw the error `websocket-incomplete-frame'."
                              nil))))))
 
 (defun websocket-read-frame (s)
-  "Read a frame and return a `websocket-frame' struct with the contents.
-This only gets complete frames. Partial frames need to wait until
+  "Read from string S a `websocket-frame' struct with the contents.
+This only gets complete frames.  Partial frames need to wait until
 the frame finishes.  If the frame is not completed, return NIL."
   (catch 'websocket-incomplete-frame
     (websocket-ensure-length s 1)
@@ -237,8 +237,8 @@ FILTER, and if the connection is closed, then 
CLOSE-CALLBACK is
 called.  Errors from FILTER function will be ignored.  You should
 catch it in the FILTER function in order to recover from the
 error.  Errors will be messaged using `messsage' function.  To
-suppress messaging errors, set `websocket-ignore-error' to `t'.
-You can log errors by setting `websocket-debug' to `t'."
+suppress messaging errors, set `websocket-ignore-error' to t.
+You can log errors by setting variable `websocket-debug' to t."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key (websocket-genkey))
@@ -293,11 +293,12 @@ You can log errors by setting `websocket-debug' to `t'."
     websocket))
 
 (defun websocket-get-debug-buffer-create (websocket)
+  "Get or create the buffer corresponding to WEBSOCKET."
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
 
 (defun websocket-error (websocket msg &rest args)
-  "Message error."
+  "Report error message MSG."
   (unless websocket-ignore-error
     (apply 'message msg args))
   (apply 'websocket-debug msg args))
@@ -314,10 +315,9 @@ You can log errors by setting `websocket-debug' to `t'."
           (insert "\n"))))))
 
 (defun websocket-verify-handshake (websocket output)
-  "Verify that OUTPUT contains a valid handshake.
-The handshake is based on the key contained in WEBSOCKET.  The
-output is assumed to have complete headers.  This function will
-either return t or call `error'."
+  "Based on WEBSOCKET's key, verify that OUTPUT contains a valid handshake.
+The output is assumed to have complete headers.  This function
+will either return t or call `error'."
   (let ((accept-string
          (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
     (websocket-debug websocket "Handshake received, checking for: %s" 
accept-string)
@@ -330,7 +330,7 @@ either return t or call `error'."
       (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
 
 (defun websocket-process-frame (websocket frame)
-  "Process FRAME returned from WEBSOCKET.
+  "Using the WEBSOCKET's filter and connection, process the FRAME.
 If the frame has a payload, the frame is passed to the filter
 slot of WEBSOCKET.  If the frame is a ping, we reply with a pong.
 If the frame is a close, we terminate the connection."
@@ -344,12 +344,14 @@ If the frame is a close, we terminate the connection."
            (delete-process (websocket-conn websocket))))))
 
 (defun websocket-outer-filter (websocket output)
-  "Removes connection strings, only passes packets."
+  "Filter the WEBSOCKET server's OUTPUT.
+This will parse headers and process frames repeatedly until there
+is no more output or the connection closes."
   (websocket-debug websocket "Received: %s" output)
   (let ((start-point)
         (end-point 0)
         (text (concat (websocket-inflight-packet websocket) output))
-        (header-end-pos))    
+        (header-end-pos))
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
     (when (and (not (websocket-header-read-p websocket))
@@ -371,12 +373,12 @@ If the frame is a close, we terminate the connection."
     (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
 
 (defun websocket-send-text (websocket text)
-  "Send TEXT to the websocket as a complete frame."
+  "To the WEBSOCKET, send TEXT as a complete frame."
   (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
                                                   :completep t)))
 
 (defun websocket-send (websocket frame)
-  "Send the FRAME to the websocket server."
+  "To the WEBSOCKET server, send the FRAME."
   (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
                    (websocket-frame-opcode frame)
                    (websocket-frame-payload frame))
@@ -387,11 +389,11 @@ If the frame is a close, we terminate the connection."
                        (websocket-encode-frame frame)))
 
 (defun websocket-openp (websocket)
-  "Returns true if the websocket exists and is open."
+  "Check WEBSOCKET and return non-nil if it is open and connected."
   (and websocket (eq 'open (process-status (websocket-conn websocket)))))
 
 (defun websocket-close (websocket)
-  "Close the websocket and erase all the old websocket data."
+  "Close WEBSOCKET and erase all the old websocket data."
   (websocket-debug websocket "Closing websocket")
   (when (websocket-openp websocket)
     (websocket-send websocket
@@ -400,7 +402,7 @@ If the frame is a close, we terminate the connection."
   (kill-buffer (process-buffer (websocket-conn websocket))))
 
 (defun websocket-ensure-connected (websocket)
-  "If the websocket connection is closed, open it."
+  "If the WEBSOCKET connection is closed, open it."
   (unless (and (websocket-conn websocket)
                (ecase (process-status (websocket-conn websocket))
                  ((run open listen) t)

commit d8fefe3ccf5c7a561b3b5a79fe6f535265d85751
Merge: 010db1c b89e002
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 26 20:06:50 2012 -0400

    Merge in rfc6455 branch

diff --cc websocket-test.el
index 39c919a,7a51c64..ed05b75
--- a/websocket-test.el
+++ b/websocket-test.el
@@@ -33,25 -32,12 +33,24 @@@
    (let* ((packet-data nil)
           (websocket
            (make-websocket :conn "fake-conn"
 -                          :filter (lambda (packet) (push packet packet-data))
 +                          :filter (lambda (packet)
 +                                    (push packet packet-data)
 +                                    (when callback (funcall callback)))
                            :close-callback (lambda (not-called) (assert nil))
-                           :url "ws://foo/bar"
-                           :v75 nil))
+                           :url "ws://foo/bar")))
 +         err-list)
      (dolist (output outputs)
 -      (websocket-outer-filter websocket output))
 -    (nreverse packet-data)))
 +      (condition-case err
 +          (websocket-outer-filter websocket output)
 +        (error (push err err-list))))
-     (list (nreverse packet-data) (nreverse err-list))))
++    (list (nreverse packet-data) (nreverse err-list)))
 +
 +(defun websocket-test-get-filtered-response (outputs)
 +  (destructuring-bind (packet-data err-list)
 +      (websocket-test-get-filtered-response-with-error outputs)
 +    (assert (eq (length err-list) 0))
 +    packet-data))
 +
  
  (ert-deftest websocket-genbytes-length ()
    (loop repeat 100
diff --cc websocket.el
index 9a8cf2d,ea493ea..ad4c1c3
--- a/websocket.el
+++ b/websocket.el
@@@ -50,13 -45,23 +45,26 @@@
  The buffer is ` *websocket URL debug*' where URL is the
  URL of the connection.")
  
 +(defvar websocket-ignore-error nil
 +  "Set to true to suppress error messages.")
 +
- (defun websocket-genbytes ()
-   "Generate bytes used at the end of the handshake."
-   (let ((s "        "))
-     (dotimes (i 8)
+ (defconst websocket-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+   "The websocket GUID as defined in RFC 6455. Do not change
+   unless the RFC changes.")
+ 
+ (defvar websocket-require-server-accept t
+   "If true, we require the correct Sec-WebSocket-Accept header
+ as part of the connection handshake.")
+ 
+ (defvar websocket-mask-frames t
+   "If true, we mask frames as defined in the spec.  This is
+ recommended to be true, and some servers will refuse to
+ communicate with unmasked clients.")
+ 
+ (defun websocket-genbytes (nbytes)
+   "Generate NBYTES random bytes."
+   (let ((s (make-string nbytes ?\s)))
+     (dotimes (i nbytes)
        (aset s i (random 256)))
      s))
  
@@@ -85,18 -229,12 +232,16 @@@ the frame finishes.  If the frame is no
  
  (defun websocket-open (url filter &optional close-callback)
    "Open a websocket connection to URL.
- Websocket packets are sent as the only argument to FILTER, and if
- the connection is closed, then CLOSE-CALLBACK is called.
- Errors from FILTER function will be ignored.  You should catch it in the
- FILTER function in order to recover from the error.  Errors will be
- messaged using `messsage' function.  To suppress messaging errors, set
- `websocket-ignore-error' to `t'.  You can log errors by setting
- `websocket-debug' to `t'."
+ `websocket-frame' structs are sent as the only argument to
+ FILTER, and if the connection is closed, then CLOSE-CALLBACK is
 -called."
++called.  Errors from FILTER function will be ignored.  You should
++catch it in the FILTER function in order to recover from the
++error.  Errors will be messaged using `messsage' function.  To
++suppress messaging errors, set `websocket-ignore-error' to `t'.
++You can log errors by setting `websocket-debug' to `t'."
    (let* ((name (format "websocket to %s" url))
           (url-struct (url-generic-parse-url url))
-          (key1-cons (websocket-genkey))
-          (key2-cons (websocket-genkey))
-          (bytes (websocket-genbytes))
+          (key (websocket-genkey))
           (buf-name (format " *%s*" name))
           (coding-system-for-read 'binary)
           (coding-system-for-write 'binary)

commit b89e002187ce932e82394023820deb8407842291
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 25 22:46:00 2012 -0400

    Test for websocket-outer-filter, plus removing some useless code from that 
function.

diff --git a/websocket-test.el b/websocket-test.el
index badc272..7a51c64 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -225,3 +225,27 @@
       (should (equal sent-frames (list
                                   (make-websocket-frame :opcode 'close
                                                         :completep t)))))))
+
+(ert-deftest websocket-outer-filter ()
+  (let* ((fake-ws (make-websocket :conn t :filter t :url t
+                                  :accept-string t :close-callback t))
+         (processed-frames)
+         (frame1 (make-websocket-frame :opcode 'text :payload "foo" :completep 
t
+                                       :length 9))
+         (frame2 (make-websocket-frame :opcode 'text :payload "bar" :completep 
t
+                                       :length 9))
+         (websocket-frames
+          (concat
+           (websocket-encode-frame frame1)
+           (websocket-encode-frame frame2))))
+    (flet ((websocket-process-frame (websocket frame)
+                                    (push frame processed-frames))
+           (websocket-verify-handshake (websocket output) t))
+      (websocket-outer-filter fake-ws "Sec-")
+      (websocket-outer-filter fake-ws "WebSocket-Accept: acceptstring")
+      (websocket-outer-filter fake-ws (concat
+                                       "\r\n\r\n"
+                                       (substring websocket-frames 0 2)))
+      (should (websocket-header-read-p fake-ws))
+      (websocket-outer-filter fake-ws (substring websocket-frames 2))
+      (should (equal (list frame2 frame1) processed-frames)))))
diff --git a/websocket.el b/websocket.el
index 1df2f22..ea493ea 100644
--- a/websocket.el
+++ b/websocket.el
@@ -350,8 +350,7 @@ If the frame is a close, we terminate the connection."
     (when (websocket-header-read-p websocket)
       (unless start-point (setq start-point 0))
       (let ((current-frame))
-        (while (and (websocket-header-read-p websocket)
-                    (setq current-frame (websocket-read-frame
+        (while (and (setq current-frame (websocket-read-frame
                                          (substring text start-point))))
           (websocket-process-frame websocket current-frame)
           (incf start-point (websocket-frame-length current-frame)))))

commit 33ff92c3d4c4066d284dc621b941c57281f8f3bd
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 25 22:00:31 2012 -0400

    Update websocket-close and test

diff --git a/websocket-test.el b/websocket-test.el
index de1fd07..badc272 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -211,3 +211,17 @@
                (websocket-encode-frame (make-websocket-frame :opcode opcode
                                                              :completep 
t))))))))
 
+(ert-deftest websocket-close ()
+  (let ((sent-frames))
+    (flet ((websocket-send (websocket frame) (push frame sent-frames))
+           (websocket-openp (websocket) t)
+           (kill-buffer (buffer))
+           (process-buffer (conn)))
+      (websocket-close (make-websocket :conn "fake-conn"
+                                       :filter t
+                                       :url t
+                                       :accept-string t
+                                       :close-callback t))
+      (should (equal sent-frames (list
+                                  (make-websocket-frame :opcode 'close
+                                                        :completep t)))))))
diff --git a/websocket.el b/websocket.el
index bba5626..1df2f22 100644
--- a/websocket.el
+++ b/websocket.el
@@ -382,7 +382,9 @@ If the frame is a close, we terminate the connection."
   "Close the websocket and erase all the old websocket data."
   (websocket-debug websocket "Closing websocket")
   (when (websocket-openp websocket)
-    (process-send-string (websocket-conn websocket) (unibyte-string ?\377?\0)))
+    (websocket-send websocket
+                    (make-websocket-frame :opcode 'close
+                                          :completep t)))
   (kill-buffer (process-buffer (websocket-conn websocket))))
 
 (defun websocket-ensure-connected (websocket)

commit 1081075d7f56a45b5dba99a760322c5dedfe7614
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 25 20:15:18 2012 -0400

    More whitespace changes

diff --git a/websocket-test.el b/websocket-test.el
index dc1a5a6..de1fd07 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -101,11 +101,12 @@
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
                                        :length (length websocket-test-hello)
                                        :completep nil)
-                 (websocket-read-frame (concat (unibyte-string
-                                                (logand (string-to-char
-                                                         (substring 
websocket-test-hello 0 1))
-                                                        127))
-                                               (substring websocket-test-hello 
1)))))
+                 (websocket-read-frame
+                  (concat (unibyte-string
+                           (logand (string-to-char
+                                    (substring websocket-test-hello 0 1))
+                                   127))
+                          (substring websocket-test-hello 1)))))
   (dotimes (i (- (length websocket-test-hello) 1))
     (should-not (websocket-read-frame
                  (substring websocket-test-hello 0
@@ -188,16 +189,20 @@
                        (websocket-frame-payload
                         (websocket-read-frame
                          (websocket-encode-frame
-                          (make-websocket-frame :opcode 'text :payload 
long-string)))))))))
+                          (make-websocket-frame :opcode 'text
+                                                :payload long-string)))))))))
   (let ((websocket-mask-frames t))
     (flet ((websocket-genbytes (n) (substring websocket-test-masked-hello 2 
6)))
       (should (equal websocket-test-masked-hello
                      (websocket-encode-frame
-                      (make-websocket-frame :opcode 'text :payload "Hello" 
:completep t))))))
+                      (make-websocket-frame :opcode 'text :payload "Hello"
+                                            :completep t))))))
   (should-not
    (websocket-frame-completep
     (websocket-read-frame
-     (websocket-encode-frame (make-websocket-frame :opcode 'text :payload 
"Hello" :completep nil)))))
+     (websocket-encode-frame (make-websocket-frame :opcode 'text
+                                                   :payload "Hello"
+                                                   :completep nil)))))
   (dolist (opcode '(close ping pong))
     (should (equal
              opcode

commit 237b190fa1f01bf133d718d973dc64dccde7d89f
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 24 22:22:17 2012 -0400

    Various whitespace changes

diff --git a/websocket-test.el b/websocket-test.el
index 435ee79..dc1a5a6 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -47,10 +47,11 @@
   ;; This example comes straight from RFC 6455
   (should
    (equal "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
-    (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
+          (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
 
 (defconst websocket-test-hello "\x81\x05\x48\x65\x6c\x6c\x6f"
   "'Hello' string example, taken from the RFC.")
+
 (defconst websocket-test-masked-hello
   "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"
   "'Hello' masked string example, taken from the RFC.")
@@ -115,16 +116,18 @@
                             (- (length websocket-test-masked-hello) (+ i 
1)))))))
 
 (defun websocket-test-make-websocket-with-accept-string (s)
-  (make-websocket :conn "fake-conn" :url "ws://foo/bar" :filter t 
:close-callback t 
-                  :accept-string s))
+  (make-websocket :conn "fake-conn" :url "ws://foo/bar" :filter t
+                  :close-callback t :accept-string s))
 
 (ert-deftest websocket-verify-handshake ()
   ;; This examples comes from the RFC
   (should (websocket-verify-handshake
-           (websocket-test-make-websocket-with-accept-string 
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+           (websocket-test-make-websocket-with-accept-string
+            "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
            "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"))
   (should-error (websocket-verify-handshake
-                 (websocket-test-make-websocket-with-accept-string 
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+                 (websocket-test-make-websocket-with-accept-string
+                  "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
                  "Sec-WebSocket-Accept: foo\r\n")))
 
 (ert-deftest websocket-process-frame ()
@@ -133,8 +136,10 @@
          (deleted)
          (websocket (make-websocket :conn "fake-conn"
                                     :url "ws://foo/bar"
-                                    :filter (lambda (frame) (setq processed
-                                                             
(websocket-frame-payload frame)))
+                                    :filter (lambda (frame)
+                                              (setq
+                                               processed
+                                               (websocket-frame-payload 
frame)))
                                     :close-callback t
                                     :accept-string "accept-string")))
     (dolist (opcode '(text binary continuation))
@@ -142,8 +147,9 @@
       (should (equal
                "hello"
                (progn
-                 (websocket-process-frame websocket
-                                          (make-websocket-frame :opcode opcode 
:payload "hello"))
+                 (websocket-process-frame
+                  websocket
+                  (make-websocket-frame :opcode opcode :payload "hello"))
                  processed))))
     (setq sent nil)
     (flet ((websocket-send (websocket content) (setq sent content)))
@@ -176,18 +182,18 @@
              websocket-test-hello
              (websocket-encode-frame
               (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
-      (dolist (len '(200 70000))
-        (let ((long-string (make-string len ?x)))
-          (should (equal long-string
-                         (websocket-frame-payload
-                          (websocket-read-frame
-                           (websocket-encode-frame
-                            (make-websocket-frame :opcode 'text :payload 
long-string)))))))))
+    (dolist (len '(200 70000))
+      (let ((long-string (make-string len ?x)))
+        (should (equal long-string
+                       (websocket-frame-payload
+                        (websocket-read-frame
+                         (websocket-encode-frame
+                          (make-websocket-frame :opcode 'text :payload 
long-string)))))))))
   (let ((websocket-mask-frames t))
     (flet ((websocket-genbytes (n) (substring websocket-test-masked-hello 2 
6)))
-        (should (equal websocket-test-masked-hello
-                   (websocket-encode-frame
-                    (make-websocket-frame :opcode 'text :payload "Hello" 
:completep t))))))
+      (should (equal websocket-test-masked-hello
+                     (websocket-encode-frame
+                      (make-websocket-frame :opcode 'text :payload "Hello" 
:completep t))))))
   (should-not
    (websocket-frame-completep
     (websocket-read-frame

commit 72a85d0491630210c1416fe93f17faf62d3b0aa9
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 24 22:20:34 2012 -0400

    Fixes to output filtering.  Also, show stack traces in the functional
    test.  The functional test now passes.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 8e7ff97..3836dfe 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -5,6 +5,7 @@
 (eval-when-compile (require 'cl))
 
 (setq websocket-debug t)
+(toggle-debug-on-error)
 
 (defvar wstest-server-buffer (get-buffer-create "*wstest-server*"))
 (defvar wstest-server-name "wstest-server")
diff --git a/websocket.el b/websocket.el
index 0035bac..bba5626 100644
--- a/websocket.el
+++ b/websocket.el
@@ -37,6 +37,7 @@
   (url (assert nil) :read-only t)
   (accept-string (assert nil))
   (handshake-accept-passed-p nil)
+  (header-read-p nil)
   (inflight-packet nil))
 
 (defvar websocket-debug nil
@@ -332,21 +333,28 @@ If the frame is a close, we terminate the connection."
 (defun websocket-outer-filter (websocket output)
   "Removes connection strings, only passes packets."
   (websocket-debug websocket "Received: %s" output)
-  (let ((start-point 0)
+  (let ((start-point)
         (end-point 0)
-        (text (concat (websocket-inflight-packet websocket) output)))
-    (setq start-point (+ 4 (string-match "\r\n\r\n" text)))
+        (text (concat (websocket-inflight-packet websocket) output))
+        (header-end-pos))    
     ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
-    (when (and websocket-require-server-accept
-               (not (websocket-handshake-accept-passed-p websocket))
-               start-point)
-      (websocket-verify-handshake websocket text))
-    (let ((current-frame))
-      (while (and start-point
-                  (setq current-frame (websocket-read-frame (substring text 
start-point))))
-        (websocket-process-frame websocket current-frame)
-        (incf start-point (websocket-frame-length current-frame))))
+    (when (and (not (websocket-header-read-p websocket))
+               (setq header-end-pos (string-match "\r\n\r\n" text))
+               (setq start-point (+ 4 header-end-pos)))
+      (setf (websocket-header-read-p websocket) t)
+      (when (and websocket-require-server-accept
+                (not (websocket-handshake-accept-passed-p websocket))
+                start-point)
+       (websocket-verify-handshake websocket text)))
+    (when (websocket-header-read-p websocket)
+      (unless start-point (setq start-point 0))
+      (let ((current-frame))
+        (while (and (websocket-header-read-p websocket)
+                    (setq current-frame (websocket-read-frame
+                                         (substring text start-point))))
+          (websocket-process-frame websocket current-frame)
+          (incf start-point (websocket-frame-length current-frame)))))
     ;; TODO(ahyatt) Rename websocket-inflight-packet (it isn't a packet)
     (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
 

commit 818c1f5103c9c0f080244840cf0043faf21f2219
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 24 22:18:46 2012 -0400

    Fix byte-compile warnings and errors

diff --git a/websocket.el b/websocket.el
index 5ef0ece..0035bac 100644
--- a/websocket.el
+++ b/websocket.el
@@ -85,7 +85,7 @@ power of 2, up to 8."
                             (aref 32-bit-parts 0) (aref 32-bit-parts 1))))
       (when (calc-eval '("$ > $$") 'pred cval most-positive-fixnum)
         (error "websocket-get-bytes: value too large to parse!"))
-      (string-to-int cval))
+      (string-to-number cval))
     ;; n is not 8
     (bindat-get-field (bindat-unpack
                      `((:val
@@ -283,7 +283,7 @@ called."
              system-name))
     (websocket-debug websocket "Websocket opened")
     websocket))
-`
+
 (defun websocket-get-debug-buffer-create (websocket)
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))

commit 0e04e15571619f29a6852c230b32e97eee2e9be8
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 24 22:00:56 2012 -0400

    Fix issue with encoding & decoding non-payload frames, and fix the
    tests that failed to catch the problem.

diff --git a/websocket-test.el b/websocket-test.el
index f885c20..435ee79 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -192,10 +192,11 @@
    (websocket-frame-completep
     (websocket-read-frame
      (websocket-encode-frame (make-websocket-frame :opcode 'text :payload 
"Hello" :completep nil)))))
-  (dolist ((opcode '(close ping pong)))
+  (dolist (opcode '(close ping pong))
     (should (equal
              opcode
              (websocket-frame-opcode
               (websocket-read-frame
-               (websocket-encode-frame (make-websocket-frame :opcode 
opcode))))))))
+               (websocket-encode-frame (make-websocket-frame :opcode opcode
+                                                             :completep 
t))))))))
 
diff --git a/websocket.el b/websocket.el
index cc29825..5ef0ece 100644
--- a/websocket.el
+++ b/websocket.el
@@ -170,10 +170,10 @@ Otherwise we throw the error 
`websocket-incomplete-frame'."
            (append (list
                     (logior (cond ((eq opcode 'continuation) 0)
                                   ((eq opcode 'text) 1)
-                                  ((eq opcode 'binary 2))
-                                  ((eq opcode 'close 8))
-                                  ((eq opcode 'ping 9))
-                                  ((eq opcode 'pong 10)))
+                                  ((eq opcode 'binary) 2)
+                                  ((eq opcode 'close) 8)
+                                  ((eq opcode 'ping) 9)
+                                  ((eq opcode 'pong) 10))
                             (if fin 128 0)))
                    (when payloadp
                      (list
@@ -187,7 +187,7 @@ Otherwise we throw the error `websocket-incomplete-frame'."
                                           (cond ((< (length payload) 126) 1)
                                                 ((< (length payload) 65536) 2)
                                                 (t 8))) nil))
-                   (when websocket-mask-frames
+                   (when (and payloadp websocket-mask-frames)
                      (append mask-key nil))
                    (when payloadp
                      (append (if websocket-mask-frames
@@ -200,14 +200,18 @@ Otherwise we throw the error 
`websocket-incomplete-frame'."
 This only gets complete frames. Partial frames need to wait until
 the frame finishes.  If the frame is not completed, return NIL."
   (catch 'websocket-incomplete-frame
-    (websocket-ensure-length s 2)
+    (websocket-ensure-length s 1)
     (let* ((opcode (websocket-get-opcode s))
-           (payload-len (websocket-get-payload-len (substring s 1)))
-           (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
            (fin (logand 128 (websocket-get-bytes s 1)))
-           (payload-start (+ (if maskp 5 1) (cdr payload-len)))
-           (payload-end (+ payload-start (car payload-len)))
-           (unmasked-payload (progn
+           (payloadp (memq opcode '(continuation text binary)))
+           (payload-len (when payloadp
+                          (websocket-get-payload-len (substring s 1))))
+           (maskp (and
+                   payloadp
+                   (= 128 (logand 128 (websocket-get-bytes (substring s 1) 
1)))))
+           (payload-start (when payloadp (+ (if maskp 5 1) (cdr payload-len))))
+           (payload-end (when payloadp (+ payload-start (car payload-len))))
+           (unmasked-payload (when payloadp
                                (websocket-ensure-length s payload-end)
                                (substring s payload-start payload-end))))
       (make-websocket-frame

commit 81bcbf7df7077db27facf0470cf9e31c18b8333e
Merge: be618da 5cb48ab
Author: Dmitry Gutov <address@hidden>
Date:   Wed May 23 10:03:15 2012 -0700

    Merge pull request #48 from lewang/master


commit 5cb48ab03c2e746bb989ff36c05b176f528b5d82
Author: Le Wang <address@hidden>
Date:   Wed May 23 23:17:41 2012 +0800

    remove duplicate js2-strict-cond-assign-warning

diff --git a/js2-mode.el b/js2-mode.el
index a2c6b7b..d01a1f4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -369,14 +369,6 @@ parenthesizing the expression, e.g. if ((a = b)) ..."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-strict-cond-assign-warning t
-  "Non-nil to warn about expressions like if (a = b).
-This often should have been '==' instead of '='.  If the warning
-is enabled, you can suppress it on a per-expression basis by
-parenthesizing the expression, e.g. if ((a = b)) ..."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-strict-var-redeclaration-warning t
   "Non-nil to warn about redeclaring variables in a script or function."
   :type 'boolean
@@ -10479,7 +10471,7 @@ If so, we don't ever want to use bounce-indent."
   ;; (examples:  doxymacs, column-marker).
   ;; To customize highlighted keywords, use `font-lock-add-keywords'.
   (setq font-lock-defaults '(nil t))
-  
+
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
       (setq js2-idle-timer-delay

commit 865fc07b6991cc215e89d1ceaeb00257195a2aca
Author: Andrew Hyatt <address@hidden>
Date:   Wed May 23 00:28:08 2012 -0400

    Require server accept in functional testing, plus fix a few issues
    that functional testing uncovered:
     - Wrong values for headers
     - Not setting completep to t in websocket-send-text

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 4aa5592..8e7ff97 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -16,6 +16,8 @@
 (defvar wstest-msgs nil)
 (defvar wstest-closed nil)
 
+(setq websocket-require-server-accept t)
+
 (defvar wstest-ws
   (websocket-open
    "ws://127.0.0.1:9999"
diff --git a/websocket.el b/websocket.el
index 9011159..cc29825 100644
--- a/websocket.el
+++ b/websocket.el
@@ -275,8 +275,8 @@ called."
                      "Sec-WebSocket-Version: 13\r\n"
                      "\r\n")
              (url-host (url-generic-parse-url url))
-             system-name
-             key))
+             key
+             system-name))
     (websocket-debug websocket "Websocket opened")
     websocket))
 `
@@ -348,7 +348,8 @@ If the frame is a close, we terminate the connection."
 
 (defun websocket-send-text (websocket text)
   "Send TEXT to the websocket as a complete frame."
-  (websocket-send websocket (make-websocket-frame :opcode 'text :payload 
text)))
+  (websocket-send websocket (make-websocket-frame :opcode 'text :payload text
+                                                  :completep t)))
 
 (defun websocket-send (websocket frame)
   "Send the FRAME to the websocket server."

commit 4b305cac3aee3ba82520834f0bfe6e201b7462d8
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 22 23:49:15 2012 -0400

    Alter functional test to work with new version.  Does not yet pass.

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index e7e849d..4aa5592 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -19,7 +19,8 @@
 (defvar wstest-ws
   (websocket-open
    "ws://127.0.0.1:9999"
-   (lambda (p) (push p wstest-msgs) (message "ws packet: %S" p))
+   (lambda (frame) (push (websocket-frame-payload frame) wstest-msgs)
+     (message "ws frame: %S" (websocket-frame-payload frame)))
    (lambda () (setq wstest-closed t))))
 
 (defun wstest-pop-to-debug ()
@@ -31,7 +32,7 @@
 (assert (websocket-openp wstest-ws))
 
 (assert (null wstest-msgs))
-(websocket-send wstest-ws "Hi!")
+(websocket-send-text wstest-ws "Hi!")
 (sleep-for 0.1)
 (assert (equal (car wstest-msgs) "You said: Hi!"))
 

commit e872ed279d1bb31b6770dd7fd00269c9d46a8e12
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 22 23:48:35 2012 -0400

    Fix some docs, adding a bit of debugging and a convenience function: 
websocket-send-text

diff --git a/websocket.el b/websocket.el
index ee800ad..9011159 100644
--- a/websocket.el
+++ b/websocket.el
@@ -224,8 +224,9 @@ the frame finishes.  If the frame is not completed, return 
NIL."
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
-Websocket packets are sent as the only argument to FILTER, and if
-the connection is closed, then CLOSE-CALLBACK is called."
+`websocket-frame' structs are sent as the only argument to
+FILTER, and if the connection is closed, then CLOSE-CALLBACK is
+called."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key (websocket-genkey))
@@ -262,7 +263,8 @@ the connection is closed, then CLOSE-CALLBACK is called."
                          (format "GET %s HTTP/1.1\r\n"
                                  (let ((path (url-filename url-struct)))
                                    (if (> (length path) 0) path "/"))))
-    (websocket-debug websocket "Sending handshake")
+    (websocket-debug websocket "Sending handshake, key: %s, acceptance: %s"
+                     key (websocket-accept-string websocket))
     (process-send-string
      conn
      (format (concat "Host: %s\r\n"
@@ -344,6 +346,10 @@ If the frame is a close, we terminate the connection."
     ;; TODO(ahyatt) Rename websocket-inflight-packet (it isn't a packet)
     (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
 
+(defun websocket-send-text (websocket text)
+  "Send TEXT to the websocket as a complete frame."
+  (websocket-send websocket (make-websocket-frame :opcode 'text :payload 
text)))
+
 (defun websocket-send (websocket frame)
   "Send the FRAME to the websocket server."
   (websocket-debug websocket "Sending frame, opcode: %s payload: %s"

commit 82e85aaac1c16ef44036d303f423cdbac16213e7
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 22 23:45:48 2012 -0400

    Fix test for websocket-genbytes

diff --git a/websocket-test.el b/websocket-test.el
index 17b20b3..f885c20 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -41,7 +41,7 @@
 
 (ert-deftest websocket-genbytes-length ()
   (loop repeat 100
-        do (should (= (string-bytes (websocket-genbytes)) 16))))
+        do (should (= (string-bytes (websocket-genbytes 16)) 16))))
 
 (ert-deftest websocket-calculate-accept ()
   ;; This example comes straight from RFC 6455

commit 655cf1e26a4d6f4a44ee8e92f0d84ab7daca7a07
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 22 23:43:43 2012 -0400

    Support outbound masking

diff --git a/websocket-test.el b/websocket-test.el
index 6a29088..17b20b3 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -171,17 +171,23 @@
 (ert-deftest websocket-encode-frame ()
   ;; We've tested websocket-read-frame, now we can use that to help
   ;; test websocket-encode-frame.
-  (should (equal
-           websocket-test-hello
-           (websocket-encode-frame
-            (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
-  (dolist (len '(200 70000))
-    (let ((long-string (make-string len ?x)))
-      (should (equal long-string
-                     (websocket-frame-payload
-                      (websocket-read-frame
-                       (websocket-encode-frame
-                        (make-websocket-frame :opcode 'text :payload 
long-string))))))))
+  (let ((websocket-mask-frames nil))
+    (should (equal
+             websocket-test-hello
+             (websocket-encode-frame
+              (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
+      (dolist (len '(200 70000))
+        (let ((long-string (make-string len ?x)))
+          (should (equal long-string
+                         (websocket-frame-payload
+                          (websocket-read-frame
+                           (websocket-encode-frame
+                            (make-websocket-frame :opcode 'text :payload 
long-string)))))))))
+  (let ((websocket-mask-frames t))
+    (flet ((websocket-genbytes (n) (substring websocket-test-masked-hello 2 
6)))
+        (should (equal websocket-test-masked-hello
+                   (websocket-encode-frame
+                    (make-websocket-frame :opcode 'text :payload "Hello" 
:completep t))))))
   (should-not
    (websocket-frame-completep
     (websocket-read-frame
diff --git a/websocket.el b/websocket.el
index 463c24d..ee800ad 100644
--- a/websocket.el
+++ b/websocket.el
@@ -52,16 +52,21 @@ URL of the connection.")
   "If true, we require the correct Sec-WebSocket-Accept header
 as part of the connection handshake.")
 
-(defun websocket-genbytes ()
-  "Generate bytes used at the end of the handshake."
-  (let ((s "                "))
-    (dotimes (i 16)
+(defvar websocket-mask-frames t
+  "If true, we mask frames as defined in the spec.  This is
+recommended to be true, and some servers will refuse to
+communicate with unmasked clients.")
+
+(defun websocket-genbytes (nbytes)
+  "Generate NBYTES random bytes."
+  (let ((s (make-string nbytes ?\s)))
+    (dotimes (i nbytes)
       (aset s i (random 256)))
     s))
 
 (defun websocket-genkey ()
   "Generate a key suitable for the websocket handshake."
-  (base64-encode-string (websocket-genbytes)))
+  (base64-encode-string (websocket-genbytes 16)))
 
 (defun websocket-calculate-accept (key)
   "Calculate the expect value of the accept header.
@@ -159,26 +164,36 @@ Otherwise we throw the error 
`websocket-incomplete-frame'."
   (let* ((opcode (websocket-frame-opcode frame))
          (payload (websocket-frame-payload frame))
          (fin (websocket-frame-completep frame))
-         (payloadp (memq opcode '(continuation text binary))))
-    (concat (unibyte-string (logior
-                             (cond ((eq opcode 'continuation) 0)
-                                   ((eq opcode 'text) 1)
-                                   ((eq opcode 'binary 2))
-                                   ((eq opcode 'close 8))
-                                   ((eq opcode 'ping 9))
-                                   ((eq opcode 'pong 10)))
-                             (if fin 128 0)))
-            (when payloadp
-              (cond ((< (length payload) 126) nil)
-                    ((< (length payload) 65536) (unibyte-string 126))
-                    (t (unibyte-string 127))))
-            (when payloadp
-              (websocket-to-bytes (length payload)
-                                   (cond ((< (length payload) 126) 1)
-                                         ((< (length payload) 65536) 2)
-                                         ((t 8)))))
-            (when payloadp
-              payload))))
+         (payloadp (memq opcode '(continuation text binary)))
+         (mask-key (when websocket-mask-frames  (websocket-genbytes 4))))
+    (apply 'unibyte-string
+           (append (list
+                    (logior (cond ((eq opcode 'continuation) 0)
+                                  ((eq opcode 'text) 1)
+                                  ((eq opcode 'binary 2))
+                                  ((eq opcode 'close 8))
+                                  ((eq opcode 'ping 9))
+                                  ((eq opcode 'pong 10)))
+                            (if fin 128 0)))
+                   (when payloadp
+                     (list
+                      (logior
+                       (if websocket-mask-frames 128 0)
+                       (cond ((< (length payload) 126) (length payload))
+                             ((< (length payload) 65536) 126)
+                             (t 127)))))
+                   (when (and payloadp (>= (length payload) 126)) 
+                     (append (websocket-to-bytes (length payload)
+                                          (cond ((< (length payload) 126) 1)
+                                                ((< (length payload) 65536) 2)
+                                                (t 8))) nil))
+                   (when websocket-mask-frames
+                     (append mask-key nil))
+                   (when payloadp
+                     (append (if websocket-mask-frames
+                                 (websocket-mask mask-key payload)
+                               payload)
+                             nil))))))
 
 (defun websocket-read-frame (s)
   "Read a frame and return a `websocket-frame' struct with the contents.

commit 75a53f12935f136508af0b52c1c439a613f32c45
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 22 21:43:15 2012 -0400

    Test websocket-encode-frame more thoroughly and fix the incomplete 
implementation

diff --git a/websocket-test.el b/websocket-test.el
index 31b682e..6a29088 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -175,6 +175,13 @@
            websocket-test-hello
            (websocket-encode-frame
             (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
+  (dolist (len '(200 70000))
+    (let ((long-string (make-string len ?x)))
+      (should (equal long-string
+                     (websocket-frame-payload
+                      (websocket-read-frame
+                       (websocket-encode-frame
+                        (make-websocket-frame :opcode 'text :payload 
long-string))))))))
   (should-not
    (websocket-frame-completep
     (websocket-read-frame
diff --git a/websocket.el b/websocket.el
index 6738dc0..463c24d 100644
--- a/websocket.el
+++ b/websocket.el
@@ -156,9 +156,10 @@ Otherwise we throw the error `websocket-incomplete-frame'."
 
 (defun websocket-encode-frame (frame)
   "Encode the FRAME struct to the binary representation."
-  (let ((opcode (websocket-frame-opcode frame))
-        (payload (websocket-frame-payload frame))
-        (fin (websocket-frame-completep frame)))
+  (let* ((opcode (websocket-frame-opcode frame))
+         (payload (websocket-frame-payload frame))
+         (fin (websocket-frame-completep frame))
+         (payloadp (memq opcode '(continuation text binary))))
     (concat (unibyte-string (logior
                              (cond ((eq opcode 'continuation) 0)
                                    ((eq opcode 'text) 1)
@@ -167,12 +168,16 @@ Otherwise we throw the error 
`websocket-incomplete-frame'."
                                    ((eq opcode 'ping 9))
                                    ((eq opcode 'pong 10)))
                              (if fin 128 0)))
-            (when (memq opcode '(continuation text binary))
+            (when payloadp
+              (cond ((< (length payload) 126) nil)
+                    ((< (length payload) 65536) (unibyte-string 126))
+                    (t (unibyte-string 127))))
+            (when payloadp
               (websocket-to-bytes (length payload)
-                                  (cond ((< (length payload) 126) 1)
-                                        ((< (length payload) 65536 2))
-                                        ((t 8)))))
-            (when (memq opcode '(continuation text binary))
+                                   (cond ((< (length payload) 126) 1)
+                                         ((< (length payload) 65536) 2)
+                                         ((t 8)))))
+            (when payloadp
               payload))))
 
 (defun websocket-read-frame (s)

commit eb912a1e53e74209b16e3d8fffa6d346371929f3
Author: Brett Hoerner <address@hidden>
Date:   Tue May 22 08:18:32 2012 -0500

    Fix let paren placement in let form.

diff --git a/coffee-mode.el b/coffee-mode.el
index cfa90a4..87a95e7 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -180,7 +180,7 @@ called `coffee-compiled-buffer-name'."
                           nil)
          (append coffee-args-compile (list "-s" "-p")))
   (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
-  (let ((buffer-file-name) "tmp.js") (set-auto-mode))
+  (let ((buffer-file-name "tmp.js")) (set-auto-mode))
   (goto-char (point-min)))
 
 (defun coffee-js2coffee-replace-region (start end)

commit 7bc2aae4a3c4f6ebdb94e5dffc7298af7f29f08e
Author: Andrew Hyatt <address@hidden>
Date:   Mon May 21 23:28:19 2012 -0400

    Make websocket-send work on frames, and use it to send pongs.

diff --git a/websocket-test.el b/websocket-test.el
index 82555be..31b682e 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -148,7 +148,7 @@
     (setq sent nil)
     (flet ((websocket-send (websocket content) (setq sent content)))
       (should (equal
-               "\xA"
+               (make-websocket-frame :opcode 'pong :completep t)
                (progn
                  (websocket-process-frame websocket
                                           (make-websocket-frame :opcode 'ping))
diff --git a/websocket.el b/websocket.el
index 55b8605..6738dc0 100644
--- a/websocket.el
+++ b/websocket.el
@@ -298,8 +298,8 @@ If the frame is a close, we terminate the connection."
     (cond ((memq opcode '(continuation text binary))
            (funcall (websocket-filter websocket) frame))
           ((eq opcode 'ping)
-           ;; \xA == pong opcode
-           (websocket-send websocket "\xA"))
+           (websocket-send websocket
+                           (make-websocket-frame :opcode 'pong :completep t)))
           ((eq opcode 'close)
            (delete-process (websocket-conn websocket))))))
 
@@ -324,13 +324,16 @@ If the frame is a close, we terminate the connection."
     ;; TODO(ahyatt) Rename websocket-inflight-packet (it isn't a packet)
     (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
 
-(defun websocket-send (websocket text)
-  "Send the raw TEXT as a websocket packet."
-  (websocket-debug websocket "Sending text: %s" text)
+(defun websocket-send (websocket frame)
+  "Send the FRAME to the websocket server."
+  (websocket-debug websocket "Sending frame, opcode: %s payload: %s"
+                   (websocket-frame-opcode frame)
+                   (websocket-frame-payload frame))
   (websocket-ensure-connected websocket)
   (unless (websocket-openp websocket)
     (error "No webserver process to send data to!"))
-  (process-send-string (websocket-conn websocket)))
+  (process-send-string (websocket-conn websocket)
+                       (websocket-encode-frame frame)))
 
 (defun websocket-openp (websocket)
   "Returns true if the websocket exists and is open."

commit 3596d846e4a7996e95fc48d6d39f507cf8b6d6e0
Author: Andrew Hyatt <address@hidden>
Date:   Mon May 21 23:17:59 2012 -0400

    Write and test websocket-encode-frame.

diff --git a/websocket-test.el b/websocket-test.el
index 09ec889..82555be 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -168,3 +168,21 @@
   (should-error (websocket-to-bytes 30 3))
   (should-error (websocket-to-bytes 300 1)))
 
+(ert-deftest websocket-encode-frame ()
+  ;; We've tested websocket-read-frame, now we can use that to help
+  ;; test websocket-encode-frame.
+  (should (equal
+           websocket-test-hello
+           (websocket-encode-frame
+            (make-websocket-frame :opcode 'text :payload "Hello" :completep 
t))))
+  (should-not
+   (websocket-frame-completep
+    (websocket-read-frame
+     (websocket-encode-frame (make-websocket-frame :opcode 'text :payload 
"Hello" :completep nil)))))
+  (dolist ((opcode '(close ping pong)))
+    (should (equal
+             opcode
+             (websocket-frame-opcode
+              (websocket-read-frame
+               (websocket-encode-frame (make-websocket-frame :opcode 
opcode))))))))
+
diff --git a/websocket.el b/websocket.el
index 5b8ef04..55b8605 100644
--- a/websocket.el
+++ b/websocket.el
@@ -154,6 +154,27 @@ Otherwise we throw the error `websocket-incomplete-frame'."
   (when (< (length s) n)
     (throw 'websocket-incomplete-frame nil)))
 
+(defun websocket-encode-frame (frame)
+  "Encode the FRAME struct to the binary representation."
+  (let ((opcode (websocket-frame-opcode frame))
+        (payload (websocket-frame-payload frame))
+        (fin (websocket-frame-completep frame)))
+    (concat (unibyte-string (logior
+                             (cond ((eq opcode 'continuation) 0)
+                                   ((eq opcode 'text) 1)
+                                   ((eq opcode 'binary 2))
+                                   ((eq opcode 'close 8))
+                                   ((eq opcode 'ping 9))
+                                   ((eq opcode 'pong 10)))
+                             (if fin 128 0)))
+            (when (memq opcode '(continuation text binary))
+              (websocket-to-bytes (length payload)
+                                  (cond ((< (length payload) 126) 1)
+                                        ((< (length payload) 65536 2))
+                                        ((t 8)))))
+            (when (memq opcode '(continuation text binary))
+              payload))))
+
 (defun websocket-read-frame (s)
   "Read a frame and return a `websocket-frame' struct with the contents.
 This only gets complete frames. Partial frames need to wait until

commit 2148c5afee6e8e2631ae0c826eeb9b04495959f7
Author: Andrew Hyatt <address@hidden>
Date:   Mon May 21 23:05:45 2012 -0400

    Create the websocket-to-bytes function, to encode a number in a
    certain amount of bytes.

diff --git a/websocket-test.el b/websocket-test.el
index c626c6d..09ec889 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -158,3 +158,13 @@
                 (websocket-process-frame websocket
                                          (make-websocket-frame :opcode 'close))
                 deleted)))))
+
+(ert-deftest websocket-to-bytes ()
+  ;; We've tested websocket-get-bytes by itself, now we can use it to
+  ;; help test websocket-to-bytes.
+  (should (equal 30 (websocket-get-bytes (websocket-to-bytes 30 1) 1)))
+  (should (equal 300 (websocket-get-bytes (websocket-to-bytes 300 2) 2)))
+  (should (equal 70000 (websocket-get-bytes (websocket-to-bytes 70000 8) 8)))
+  (should-error (websocket-to-bytes 30 3))
+  (should-error (websocket-to-bytes 300 1)))
+
diff --git a/websocket.el b/websocket.el
index 3bdb883..5b8ef04 100644
--- a/websocket.el
+++ b/websocket.el
@@ -91,6 +91,26 @@ power of 2, up to 8."
                                    "websocket-get-bytes: Unknown N: %s" n)))))
                      s) :val)))
 
+(defun websocket-to-bytes (val nbytes)
+  "Encode the integer VAL in NBYTES of data.
+NBYTES much be a power of 2, up to 8."
+  (unless (or (and (< nbytes 8)
+                   (< val (expt 2 (* 8 nbytes))))
+              (and (= nbytes 8)
+                   (calc-eval "% < 2^(8 * %%)" 'pred val nbytes)))
+      (error "websocket-to-bytes: Value %d could not be expressed in %d bytes"
+             val nbytes))
+  (if (= nbytes 8)
+      (bindat-pack `((:val vec 2 u32))
+                   `((:val . [,(/ val 4294967296)
+                              ,(mod val 4294967296)])))
+    (bindat-pack
+     `((:val ,(cond ((= nbytes 1) 'u8)
+                    ((= nbytes 2) 'u16)
+                    ((= nbytes 4) 'u32)
+                    (t (error "websocket-to-bytes: Unknown NBYTES: %s" 
nbytes)))))
+     `((:val . ,val)))))
+
 (defun websocket-get-opcode (s)
   "Retrieve the opcode from the dword at the start of the frame
 given by string."

commit 8fd1f742cade458446cb197a256f9b117948550d
Author: Andrew Hyatt <address@hidden>
Date:   Mon May 21 22:19:26 2012 -0400

    Remove unused function websocket-random-insert

diff --git a/websocket.el b/websocket.el
index ef039a3..3bdb883 100644
--- a/websocket.el
+++ b/websocket.el
@@ -59,12 +59,6 @@ as part of the connection handshake.")
       (aset s i (random 256)))
     s))
 
-(defun websocket-random-insert (str-to-insert target-str)
-  "Insert STR-TO-INSERT at a random position in TARGET-STR."
-  (let ((r (+ 1 (random (- (length target-str) 2)))))
-    (concat (substring target-str 0 r) str-to-insert
-            (substring target-str r))))
-
 (defun websocket-genkey ()
   "Generate a key suitable for the websocket handshake."
   (base64-encode-string (websocket-genbytes)))

commit b0a2970d51f85c5dc076bd22cb89eb06c01a36e3
Author: Andrew Hyatt <address@hidden>
Date:   Mon May 21 21:47:27 2012 -0400

    Add completep in frame

diff --git a/websocket-test.el b/websocket-test.el
index eeb2f59..c626c6d 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -85,15 +85,26 @@
 
 (ert-deftest websocket-read-frame ()
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
-                                       :length (length websocket-test-hello))
+                                       :length (length websocket-test-hello)
+                                       :completep t)
                  (websocket-read-frame websocket-test-hello)))
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
-                                       :length (length websocket-test-hello))
+                                       :length (length websocket-test-hello)
+                                       :completep t)
                  (websocket-read-frame (concat websocket-test-hello
                                                "should-not-be-read"))))
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
-                                       :length (length 
websocket-test-masked-hello))
+                                       :length (length 
websocket-test-masked-hello)
+                                       :completep t)
                  (websocket-read-frame websocket-test-masked-hello)))
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
+                                       :length (length websocket-test-hello)
+                                       :completep nil)
+                 (websocket-read-frame (concat (unibyte-string
+                                                (logand (string-to-char
+                                                         (substring 
websocket-test-hello 0 1))
+                                                        127))
+                                               (substring websocket-test-hello 
1)))))
   (dotimes (i (- (length websocket-test-hello) 1))
     (should-not (websocket-read-frame
                  (substring websocket-test-hello 0
diff --git a/websocket.el b/websocket.el
index fd50080..ef039a3 100644
--- a/websocket.el
+++ b/websocket.el
@@ -123,7 +123,7 @@ many bytes were consumed from the string."
            (cons (websocket-get-bytes (substring s 1) 2) 3))
           (t (cons initial-val 1)))))
 
-(defstruct websocket-frame opcode payload length)
+(defstruct websocket-frame opcode payload length completep)
 
 (defun websocket-mask (key data)
   "Mask string DATA with string KEY according to the RFC.
@@ -149,21 +149,23 @@ the frame finishes.  If the frame is not completed, 
return NIL."
     (let* ((opcode (websocket-get-opcode s))
            (payload-len (websocket-get-payload-len (substring s 1)))
            (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
+           (fin (logand 128 (websocket-get-bytes s 1)))
            (payload-start (+ (if maskp 5 1) (cdr payload-len)))
            (payload-end (+ payload-start (car payload-len)))
            (unmasked-payload (progn
                                (websocket-ensure-length s payload-end)
                                (substring s payload-start payload-end))))
-      (if maskp
-          (let ((masking-key (substring s (+ 1 (cdr payload-len))
-                                        (+ 5 (cdr payload-len)))))
-            (make-websocket-frame :opcode opcode
-                                  :payload
-                                  (websocket-mask masking-key unmasked-payload)
-                                  :length payload-end))
-        (make-websocket-frame :opcode opcode
-                              :payload unmasked-payload
-                              :length payload-end)))))
+      (make-websocket-frame
+       :opcode opcode
+       :payload
+       (if maskp
+           (let ((masking-key (substring s (+ 1 (cdr payload-len))
+                                         (+ 5 (cdr payload-len)))))
+             (websocket-mask masking-key unmasked-payload))
+         unmasked-payload
+         )
+       :length payload-end
+       :completep (> fin 0)))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit 3a7798fbe921b2eec3991ab113d4c2d3630afec5
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 20 23:19:44 2012 -0400

    Added frame processing, and more of the structure to use it.

diff --git a/websocket-test.el b/websocket-test.el
index 80d9295..eeb2f59 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -104,7 +104,7 @@
                             (- (length websocket-test-masked-hello) (+ i 
1)))))))
 
 (defun websocket-test-make-websocket-with-accept-string (s)
-  (make-websocket :conn "fake-conn" :url "ws://fo/bar" :filter t 
:close-callback t 
+  (make-websocket :conn "fake-conn" :url "ws://foo/bar" :filter t 
:close-callback t 
                   :accept-string s))
 
 (ert-deftest websocket-verify-handshake ()
@@ -115,3 +115,35 @@
   (should-error (websocket-verify-handshake
                  (websocket-test-make-websocket-with-accept-string 
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
                  "Sec-WebSocket-Accept: foo\r\n")))
+
+(ert-deftest websocket-process-frame ()
+  (let* ((sent)
+         (processed)
+         (deleted)
+         (websocket (make-websocket :conn "fake-conn"
+                                    :url "ws://foo/bar"
+                                    :filter (lambda (frame) (setq processed
+                                                             
(websocket-frame-payload frame)))
+                                    :close-callback t
+                                    :accept-string "accept-string")))
+    (dolist (opcode '(text binary continuation))
+      (setq processed nil)
+      (should (equal
+               "hello"
+               (progn
+                 (websocket-process-frame websocket
+                                          (make-websocket-frame :opcode opcode 
:payload "hello"))
+                 processed))))
+    (setq sent nil)
+    (flet ((websocket-send (websocket content) (setq sent content)))
+      (should (equal
+               "\xA"
+               (progn
+                 (websocket-process-frame websocket
+                                          (make-websocket-frame :opcode 'ping))
+                 sent))))
+    (flet ((delete-process (conn) (setq deleted t)))
+      (should (progn
+                (websocket-process-frame websocket
+                                         (make-websocket-frame :opcode 'close))
+                deleted)))))
diff --git a/websocket.el b/websocket.el
index f6a343e..fd50080 100644
--- a/websocket.el
+++ b/websocket.el
@@ -252,6 +252,20 @@ either return t or call `error'."
           t)
       (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
 
+(defun websocket-process-frame (websocket frame)
+  "Process FRAME returned from WEBSOCKET.
+If the frame has a payload, the frame is passed to the filter
+slot of WEBSOCKET.  If the frame is a ping, we reply with a pong.
+If the frame is a close, we terminate the connection."
+  (let ((opcode (websocket-frame-opcode frame)))
+    (cond ((memq opcode '(continuation text binary))
+           (funcall (websocket-filter websocket) frame))
+          ((eq opcode 'ping)
+           ;; \xA == pong opcode
+           (websocket-send websocket "\xA"))
+          ((eq opcode 'close)
+           (delete-process (websocket-conn websocket))))))
+
 (defun websocket-outer-filter (websocket output)
   "Removes connection strings, only passes packets."
   (websocket-debug websocket "Received: %s" output)
@@ -265,21 +279,13 @@ either return t or call `error'."
                (not (websocket-handshake-accept-passed-p websocket))
                start-point)
       (websocket-verify-handshake websocket text))
-    (while (and start-point
-                (setq end-point
-                      (string-match "\377" text start-point)))
-        (funcall (websocket-filter websocket)
-                 (substring text (+ 1 start-point) end-point))
-        (setq start-point (string-match "\0" text end-point)))
-      (let* ((next-start (or start-point
-                                     (when end-point
-                                       (or (string-match "\0" text end-point)
-                                           (- (length text) 1)))
-                                     0))
-             (next-end (or (string-match "\377" text next-start)
-                            (length text))))
-        (setf (websocket-inflight-packet websocket)
-              (concat (substring text next-start next-end))))))
+    (let ((current-frame))
+      (while (and start-point
+                  (setq current-frame (websocket-read-frame (substring text 
start-point))))
+        (websocket-process-frame websocket current-frame)
+        (incf start-point (websocket-frame-length current-frame))))
+    ;; TODO(ahyatt) Rename websocket-inflight-packet (it isn't a packet)
+    (setf (websocket-inflight-packet websocket) (substring text (or 
start-point 0)))))
 
 (defun websocket-send (websocket text)
   "Send the raw TEXT as a websocket packet."
@@ -287,9 +293,7 @@ either return t or call `error'."
   (websocket-ensure-connected websocket)
   (unless (websocket-openp websocket)
     (error "No webserver process to send data to!"))
-  (process-send-string (websocket-conn websocket)
-                       (concat (unibyte-string ?\0) text
-                               (unibyte-string ?\377))))
+  (process-send-string (websocket-conn websocket)))
 
 (defun websocket-openp (websocket)
   "Returns true if the websocket exists and is open."

commit 7900cdaed05644be1bac7a0cf01ed767eaf8ee3b
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 20 14:15:03 2012 -0400

    Return the length of the websocket frame from websocket-read-frame.

diff --git a/websocket-test.el b/websocket-test.el
index c6b7e54..80d9295 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -84,9 +84,15 @@
                                  (:val . [0 70000])))))))
 
 (ert-deftest websocket-read-frame ()
-  (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
+                                       :length (length websocket-test-hello))
                  (websocket-read-frame websocket-test-hello)))
-  (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
+                                       :length (length websocket-test-hello))
+                 (websocket-read-frame (concat websocket-test-hello
+                                               "should-not-be-read"))))
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello"
+                                       :length (length 
websocket-test-masked-hello))
                  (websocket-read-frame websocket-test-masked-hello)))
   (dotimes (i (- (length websocket-test-hello) 1))
     (should-not (websocket-read-frame
diff --git a/websocket.el b/websocket.el
index 47d4df4..f6a343e 100644
--- a/websocket.el
+++ b/websocket.el
@@ -123,7 +123,7 @@ many bytes were consumed from the string."
            (cons (websocket-get-bytes (substring s 1) 2) 3))
           (t (cons initial-val 1)))))
 
-(defstruct websocket-frame opcode payload)
+(defstruct websocket-frame opcode payload length)
 
 (defun websocket-mask (key data)
   "Mask string DATA with string KEY according to the RFC.
@@ -149,23 +149,21 @@ the frame finishes.  If the frame is not completed, 
return NIL."
     (let* ((opcode (websocket-get-opcode s))
            (payload-len (websocket-get-payload-len (substring s 1)))
            (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
+           (payload-start (+ (if maskp 5 1) (cdr payload-len)))
+           (payload-end (+ payload-start (car payload-len)))
            (unmasked-payload (progn
-                               (websocket-ensure-length s (+ (if maskp 5 1)
-                                                             (car payload-len)
-                                                             (cdr 
payload-len)))
-                               (substring
-                                s
-                                (+ (if maskp 5 1) (cdr payload-len))
-                                (+ (if maskp 5 1) (car payload-len)
-                                   (cdr payload-len))))))
+                               (websocket-ensure-length s payload-end)
+                               (substring s payload-start payload-end))))
       (if maskp
           (let ((masking-key (substring s (+ 1 (cdr payload-len))
                                         (+ 5 (cdr payload-len)))))
             (make-websocket-frame :opcode opcode
                                   :payload
-                                  (websocket-mask masking-key 
unmasked-payload)))
+                                  (websocket-mask masking-key unmasked-payload)
+                                  :length payload-end))
         (make-websocket-frame :opcode opcode
-                              :payload unmasked-payload)))))
+                              :payload unmasked-payload
+                              :length payload-end)))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit c619af744cfa60cd5b7db1b522cedd35d46dc91a
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 20 13:55:45 2012 -0400

    Pass text instead of output to verification.

diff --git a/websocket.el b/websocket.el
index 94923d1..47d4df4 100644
--- a/websocket.el
+++ b/websocket.el
@@ -266,7 +266,7 @@ either return t or call `error'."
     (when (and websocket-require-server-accept
                (not (websocket-handshake-accept-passed-p websocket))
                start-point)
-      (websocket-verify-handshake websocket output))
+      (websocket-verify-handshake websocket text))
     (while (and start-point
                 (setq end-point
                       (string-match "\377" text start-point)))

commit 8da9119fc555dac0be20b1f26b528e3dfa1e5695
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 20 13:54:45 2012 -0400

    Separate out the handshake verification logic, and test it.  Look for
    the end of headers instead of the first packet before testing
    handshake verification.

diff --git a/websocket-test.el b/websocket-test.el
index 3273a39..c6b7e54 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -96,3 +96,16 @@
     (should-not (websocket-read-frame
                  (substring websocket-test-masked-hello 0
                             (- (length websocket-test-masked-hello) (+ i 
1)))))))
+
+(defun websocket-test-make-websocket-with-accept-string (s)
+  (make-websocket :conn "fake-conn" :url "ws://fo/bar" :filter t 
:close-callback t 
+                  :accept-string s))
+
+(ert-deftest websocket-verify-handshake ()
+  ;; This examples comes from the RFC
+  (should (websocket-verify-handshake
+           (websocket-test-make-websocket-with-accept-string 
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+           "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"))
+  (should-error (websocket-verify-handshake
+                 (websocket-test-make-websocket-with-accept-string 
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+                 "Sec-WebSocket-Accept: foo\r\n")))
diff --git a/websocket.el b/websocket.el
index 5398831..94923d1 100644
--- a/websocket.el
+++ b/websocket.el
@@ -222,7 +222,7 @@ the connection is closed, then CLOSE-CALLBACK is called."
              key))
     (websocket-debug websocket "Websocket opened")
     websocket))
-
+`
 (defun websocket-get-debug-buffer-create (websocket)
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
@@ -238,26 +238,35 @@ the connection is closed, then CLOSE-CALLBACK is called."
           (insert (apply 'format (append (list msg) args)))
           (insert "\n"))))))
 
+(defun websocket-verify-handshake (websocket output)
+  "Verify that OUTPUT contains a valid handshake.
+The handshake is based on the key contained in WEBSOCKET.  The
+output is assumed to have complete headers.  This function will
+either return t or call `error'."
+  (let ((accept-string
+         (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
+    (websocket-debug websocket "Handshake received, checking for: %s" 
accept-string)
+    (if (string-match (regexp-quote accept-string) output)
+        (progn
+          (setf (websocket-handshake-accept-passed-p websocket) t)
+          (websocket-debug websocket "Handshake accepted")
+          ;; return true
+          t)
+      (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
+
 (defun websocket-outer-filter (websocket output)
   "Removes connection strings, only passes packets."
   (websocket-debug websocket "Received: %s" output)
   (let ((start-point 0)
         (end-point 0)
         (text (concat (websocket-inflight-packet websocket) output)))
-    (setq start-point (string-match "\0" text))
-    ;; If we've received the first packet, check to see if we've
+    (setq start-point (+ 4 (string-match "\r\n\r\n" text)))
+    ;; If we've received the complete header, check to see if we've
     ;; received the desired handshake.
     (when (and websocket-require-server-accept
                (not (websocket-handshake-accept-passed-p websocket))
                start-point)
-      (let ((accept-string
-             (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
-        (websocket-debug websocket "Handshake received, checking for: %s" 
accept-string)
-        (if (string-match (regexp-quote accept-string) text)
-            (progn
-              (setf (websocket-handshake-accept-passed-p websocket) t)
-              (websocket-debug websocket "Handshake accepted"))
-        (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
+      (websocket-verify-handshake websocket output))
     (while (and start-point
                 (setq end-point
                       (string-match "\377" text start-point)))

commit 51b5764a74fbd45c106c0abc9d072132a7c3ebfa
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 19 20:19:53 2012 -0400

    Ensure the websocket frame is complete, and return NIL if not.

diff --git a/websocket-test.el b/websocket-test.el
index f8949ba..3273a39 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -87,4 +87,12 @@
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
                  (websocket-read-frame websocket-test-hello)))
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
-                 (websocket-read-frame websocket-test-masked-hello))))
+                 (websocket-read-frame websocket-test-masked-hello)))
+  (dotimes (i (- (length websocket-test-hello) 1))
+    (should-not (websocket-read-frame
+                 (substring websocket-test-hello 0
+                            (- (length websocket-test-hello) (+ i 1))))))
+  (dotimes (i (- (length websocket-test-masked-hello) 1))
+    (should-not (websocket-read-frame
+                 (substring websocket-test-masked-hello 0
+                            (- (length websocket-test-masked-hello) (+ i 
1)))))))
diff --git a/websocket.el b/websocket.el
index f04fa4d..5398831 100644
--- a/websocket.el
+++ b/websocket.el
@@ -100,6 +100,7 @@ power of 2, up to 8."
 (defun websocket-get-opcode (s)
   "Retrieve the opcode from the dword at the start of the frame
 given by string."
+  (websocket-ensure-length s 1)
   (let ((opcode (logand #xf (websocket-get-bytes s 1))))
     (cond ((= opcode 0) 'continuation)
           ((= opcode 1) 'text)
@@ -112,10 +113,13 @@ given by string."
   "Parses out the payload length from the string.
 We start at position 0, and return a cons of the payload length and how
 many bytes were consumed from the string."
+  (websocket-ensure-length s 1)
   (let* ((initial-val (logand 127 (websocket-get-bytes s 1))))
     (cond ((= initial-val 127)
+           (websocket-ensure-length s 9)
            (cons (websocket-get-bytes (substring s 1) 8) 9))
           ((= initial-val 126)
+           (websocket-ensure-length s 3)
            (cons (websocket-get-bytes (substring s 1) 2) 3))
           (t (cons initial-val 1)))))
 
@@ -130,24 +134,38 @@ This is used to both mask and unmask data."
          for i from 0 to (length data)
          collect (logxor (websocket-get-bytes (substring key (mod i 4)) 1) 
b))))
 
+(defun websocket-ensure-length (s n)
+  "Ensure the string S has at most N bytes.
+Otherwise we throw the error `websocket-incomplete-frame'."
+  (when (< (length s) n)
+    (throw 'websocket-incomplete-frame nil)))
+
 (defun websocket-read-frame (s)
-  "Read a frame and return a `websocket-frame' struct with the contents."
-  (let* ((opcode (websocket-get-opcode s))
-         (payload-len (websocket-get-payload-len (substring s 1)))
-         (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
-         (unmasked-payload (substring
-                            s
-                            (+ (if maskp 5 1) (cdr payload-len))
-                            (+ (if maskp 5 1) (car payload-len)
-                               (cdr payload-len)))))
-    (if maskp
-        (let ((masking-key (substring s (+ 1 (cdr payload-len))
-                                      (+ 5 (cdr payload-len)))))
-          (make-websocket-frame :opcode opcode
-                                :payload
-                                (websocket-mask masking-key unmasked-payload)))
-      (make-websocket-frame :opcode opcode
-                          :payload unmasked-payload))))
+  "Read a frame and return a `websocket-frame' struct with the contents.
+This only gets complete frames. Partial frames need to wait until
+the frame finishes.  If the frame is not completed, return NIL."
+  (catch 'websocket-incomplete-frame
+    (websocket-ensure-length s 2)
+    (let* ((opcode (websocket-get-opcode s))
+           (payload-len (websocket-get-payload-len (substring s 1)))
+           (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
+           (unmasked-payload (progn
+                               (websocket-ensure-length s (+ (if maskp 5 1)
+                                                             (car payload-len)
+                                                             (cdr 
payload-len)))
+                               (substring
+                                s
+                                (+ (if maskp 5 1) (cdr payload-len))
+                                (+ (if maskp 5 1) (car payload-len)
+                                   (cdr payload-len))))))
+      (if maskp
+          (let ((masking-key (substring s (+ 1 (cdr payload-len))
+                                        (+ 5 (cdr payload-len)))))
+            (make-websocket-frame :opcode opcode
+                                  :payload
+                                  (websocket-mask masking-key 
unmasked-payload)))
+        (make-websocket-frame :opcode opcode
+                              :payload unmasked-payload)))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit 010db1c60172ea6e62906ab4cb39c47508e2f629
Merge: c0669ae b5d4b03
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 19 16:32:13 2012 -0700

    Merge pull request #9 from tkf/robust-outer-filter
    
    Ignore errors occurred in the user specified filter


commit c0669aea52898002f35560e689a07d58aee4f915
Merge: fbee950 722b4b7
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 19 16:29:42 2012 -0700

    Merge pull request #10 from tkf/remove-lexical-let
    
    Get rid of lexical-let


commit 722b4b71b86862911e407ac69f68a50d9b9e436a
Author: Takafumi Arakaki <address@hidden>
Date:   Sat May 19 19:31:31 2012 +0200

    Get rid of lexical-let
    
    Emacs process object has a plist to hold miscellaneous values.
    The `websocket' object is now stored in this plist so that it
    can be retrieved from the first `process' argument of the filter
    and sentinel callback functions.
    
    See also:
    
http://www.gnu.org/software/emacs/manual/html_node/elisp/Process-Information.html

diff --git a/websocket.el b/websocket.el
index 78a0ecf..d06089a 100644
--- a/websocket.el
+++ b/websocket.el
@@ -104,18 +104,21 @@ the connection is closed, then CLOSE-CALLBACK is called."
          (websocket (make-websocket :conn conn :url url :filter filter
                                     :close-callback close-callback
                                     :v75 websocket-use-v75)))
-    (lexical-let ((websocket websocket))
-      (set-process-filter conn
-                          (lambda (process output)
-                            (websocket-outer-filter websocket output)))
-      (when close-callback
-        (set-process-sentinel conn
-                              (lambda (process change)
-                                (websocket-debug websocket
-                                                 "State change to %s" change)
-                                (unless (websocket-openp websocket)
-                                  (funcall (websocket-close-callback
-                                            websocket)))))))
+    (process-put conn :websocket websocket)
+    (set-process-filter conn
+                        (lambda (process output)
+                          (let ((websocket (process-get process :websocket)))
+                            (websocket-outer-filter websocket output))))
+    (when close-callback
+      (set-process-sentinel
+       conn
+       (lambda (process change)
+         (let ((websocket (process-get process :websocket)))
+           (websocket-debug websocket
+                            "State change to %s" change)
+           (unless (websocket-openp websocket)
+             (funcall (websocket-close-callback
+                       websocket)))))))
     (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"

commit 4390cc2ef3e52f71fde252f73d8dc62daeb83f60
Author: Dmitry Gutov <address@hidden>
Date:   Sat May 19 16:18:27 2012 +0400

    Remove leftover accumulator; require js2-mode

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 6ee293b..a85a41d 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -1,6 +1,8 @@
 (eval-when-compile
   (require 'cl))
 
+(require 'js2-mode)
+
 (defconst js2-imenu-extension-styles
   `((:framework jquery
      :call-re   "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
@@ -56,15 +58,12 @@ in a shared namespace."
                           (concat "\\(" (plist-get style :call-re) "\\)"))
                         styles "\\|"))
          ;; Dynamic scoping. Ew.
-         (js2-mode-ast root)
-         chains)
+         (js2-mode-ast root))
     (goto-char (point-min))
     (while (js-re-search-forward re nil t)
-      (push (loop for i from 0 to (1- (length styles))
-                  when (match-beginning (1+ i))
-                  return (funcall (plist-get (nth i styles) :recorder)))
-            chains))
-    chains))
+      (loop for i from 0 to (1- (length styles))
+            when (match-beginning (1+ i))
+            return (funcall (plist-get (nth i styles) :recorder))))))
 
 (defun js2-imenu-record-jquery-extend ()
   (let ((pred (lambda (subject)

commit 4c8dbe2568fdb9039ef81665ff6c1a490b9c655f
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 19 00:14:06 2012 -0400

    Implement masking and unmasking.

diff --git a/websocket-test.el b/websocket-test.el
index 8c346ba..f8949ba 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -51,6 +51,9 @@
 
 (defconst websocket-test-hello "\x81\x05\x48\x65\x6c\x6c\x6f"
   "'Hello' string example, taken from the RFC.")
+(defconst websocket-test-masked-hello
+  "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"
+  "'Hello' masked string example, taken from the RFC.")
 
 (ert-deftest websocket-get-bytes ()
   (should (equal #x5 (websocket-get-bytes "\x5" 1)))
@@ -82,4 +85,6 @@
 
 (ert-deftest websocket-read-frame ()
   (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
-                 (websocket-read-frame websocket-test-hello))))
+                 (websocket-read-frame websocket-test-hello)))
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
+                 (websocket-read-frame websocket-test-masked-hello))))
diff --git a/websocket.el b/websocket.el
index f824059..f04fa4d 100644
--- a/websocket.el
+++ b/websocket.el
@@ -121,15 +121,33 @@ many bytes were consumed from the string."
 
 (defstruct websocket-frame opcode payload)
 
+(defun websocket-mask (key data)
+  "Mask string DATA with string KEY according to the RFC.
+This is used to both mask and unmask data."
+  (apply
+   'string
+   (loop for b across data
+         for i from 0 to (length data)
+         collect (logxor (websocket-get-bytes (substring key (mod i 4)) 1) 
b))))
+
 (defun websocket-read-frame (s)
   "Read a frame and return a `websocket-frame' struct with the contents."
-  (let ((opcode (websocket-get-opcode s))
-        (payload-len (websocket-get-payload-len (substring s 1)))
-        (maskp (= 128 (logand 128 (websocket-get-bytes s 1)))))
-    (make-websocket-frame :opcode opcode
-                          :payload (substring s (+ 1 (cdr payload-len))
-                                              (+ 1 (car payload-len)
-                                                 (cdr payload-len))))))
+  (let* ((opcode (websocket-get-opcode s))
+         (payload-len (websocket-get-payload-len (substring s 1)))
+         (maskp (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))
+         (unmasked-payload (substring
+                            s
+                            (+ (if maskp 5 1) (cdr payload-len))
+                            (+ (if maskp 5 1) (car payload-len)
+                               (cdr payload-len)))))
+    (if maskp
+        (let ((masking-key (substring s (+ 1 (cdr payload-len))
+                                      (+ 5 (cdr payload-len)))))
+          (make-websocket-frame :opcode opcode
+                                :payload
+                                (websocket-mask masking-key unmasked-payload)))
+      (make-websocket-frame :opcode opcode
+                          :payload unmasked-payload))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit ae51a782544fbaa9e67ebc5056c0d93cd3121168
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 18 23:46:08 2012 -0400

    Code to read a frame.  Does not yet support masking.

diff --git a/websocket-test.el b/websocket-test.el
index 93d0492..8c346ba 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -79,3 +79,7 @@
                   (bindat-pack '((:len u8) (:val vec 2 u32))
                                `((:len . 127)
                                  (:val . [0 70000])))))))
+
+(ert-deftest websocket-read-frame ()
+  (should (equal (make-websocket-frame :opcode 'text :payload "Hello")
+                 (websocket-read-frame websocket-test-hello))))
diff --git a/websocket.el b/websocket.el
index fcee184..f824059 100644
--- a/websocket.el
+++ b/websocket.el
@@ -119,6 +119,18 @@ many bytes were consumed from the string."
            (cons (websocket-get-bytes (substring s 1) 2) 3))
           (t (cons initial-val 1)))))
 
+(defstruct websocket-frame opcode payload)
+
+(defun websocket-read-frame (s)
+  "Read a frame and return a `websocket-frame' struct with the contents."
+  (let ((opcode (websocket-get-opcode s))
+        (payload-len (websocket-get-payload-len (substring s 1)))
+        (maskp (= 128 (logand 128 (websocket-get-bytes s 1)))))
+    (make-websocket-frame :opcode opcode
+                          :payload (substring s (+ 1 (cdr payload-len))
+                                              (+ 1 (car payload-len)
+                                                 (cdr payload-len))))))
+
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
 Websocket packets are sent as the only argument to FILTER, and if

commit e5925a9de31ff070b8f7b2781d0e75f8c8b37258
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 18 23:36:05 2012 -0400

    Switched around the conditions in websocket-get-payload-len to be easier to 
read.

diff --git a/websocket.el b/websocket.el
index 2748e8b..fcee184 100644
--- a/websocket.el
+++ b/websocket.el
@@ -113,11 +113,11 @@ given by string."
 We start at position 0, and return a cons of the payload length and how
 many bytes were consumed from the string."
   (let* ((initial-val (logand 127 (websocket-get-bytes s 1))))
-    (cond ((< initial-val 126)
-           (cons initial-val 1))
+    (cond ((= initial-val 127)
+           (cons (websocket-get-bytes (substring s 1) 8) 9))
           ((= initial-val 126)
            (cons (websocket-get-bytes (substring s 1) 2) 3))
-          (t (cons (websocket-get-bytes (substring s 1) 8) 9)))))
+          (t (cons initial-val 1)))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit b948e95ad982fe5bb17ce671f2566dcc1e22212a
Author: Andrew Hyatt <address@hidden>
Date:   Fri May 18 23:31:55 2012 -0400

    Fixed payload len logic, and rewrote the bit-grabbing bits to just
    work on bytes, which is much easier and faster.

diff --git a/websocket-test.el b/websocket-test.el
index 8decc26..93d0492 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -49,36 +49,33 @@
    (equal "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
     (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
 
-(ert-deftest websocket-get-bits ()
-  ;; 0         1         2         3
-  ;; 01234567890123456789012345678901
-  ;; For testing, let's use this fairly random sequence
-  ;; 01010001000100101011011110010101
-  ;; = 
-  (let ((test-num 1360181141))
-    (should (equal 1 (websocket-get-bits test-num 0 1)))
-    (should (equal 1 (websocket-get-bits test-num 30 31)))
-    ;; 16-20 = 10110
-    (should (equal 22 (websocket-get-bits test-num 16 20)))))
-
 (defconst websocket-test-hello "\x81\x05\x48\x65\x6c\x6c\x6f"
   "'Hello' string example, taken from the RFC.")
 
+(ert-deftest websocket-get-bytes ()
+  (should (equal #x5 (websocket-get-bytes "\x5" 1)))
+  (should (equal #x101 (websocket-get-bytes "\x1\x1" 2)))
+  (should (equal #x100000001
+                 (websocket-get-bytes "\x0\x0\x0\x1\x0\x0\x0\x1" 8)))
+  (should-error (websocket-get-bytes "\x0\x0\x0" 3))
+  (should-error (websocket-get-bytes "\x0" 2)))
+
 (ert-deftest websocket-get-opcode ()
   (should (equal 'text (websocket-get-opcode websocket-test-hello))))
 
 (ert-deftest websocket-get-payload-len ()
-  (should (equal '(5 . 0)
-                 (websocket-get-payload-len websocket-test-hello)))
+  (should (equal '(5 . 1)
+                 (websocket-get-payload-len
+                  (substring websocket-test-hello 1))))
   (should (equal '(200 . 3)
                  (websocket-get-payload-len
-                  (bindat-pack '((:len u32) (:val u16))
-                               `((:len . ,(lsh 126 16))
+                  (bindat-pack '((:len u8) (:val u16))
+                               `((:len . 126)
                                  (:val . 200))))))
   ;; we don't want to hit up any limits even on strange emacs builds,
   ;; so this test has a pretty small test value
   (should (equal '(70000 . 9)
                  (websocket-get-payload-len
-                  (bindat-pack '((:len u32) (:val vec 2 u32))
-                               `((:len . ,(lsh 127 16))
+                  (bindat-pack '((:len u8) (:val vec 2 u32))
+                               `((:len . 127)
                                  (:val . [0 70000])))))))
diff --git a/websocket.el b/websocket.el
index 0e8d4f2..2748e8b 100644
--- a/websocket.el
+++ b/websocket.el
@@ -75,28 +75,32 @@ This is based on the KEY from the Sec-WebSocket-Key header."
   (base64-encode-string
    (sha1 (concat key websocket-guid) nil nil t)))
 
-(defun websocket-get-bits (dword start-bit end-bit)
-  "Return the value of DWORD between START-BIT and END-BIT.
-START-BIT must be less than END-BIT.  The range is inclusive at
-both ends.  Although the ordering of bits is big-endian the bits
-are numbed most significant first.  That is, the most
-significant, leftmost bit is 0."
-  (when (> start-bit end-bit)
-      (error
-       "In websocket-get-bits: Start bit must be less than end-bit."))
-  (logand (lsh dword (- (- 31 end-bit)))
-          (loop for i from 0 upto
-                (- end-bit start-bit)
-                sum (expt 2 i))))
-
-(defun websocket-get-dword (s)
-  "From string S, retrieve the first dword."
-  (bindat-get-field (bindat-unpack '((:val dword)) s) :val))
+(defun websocket-get-bytes (s n)
+  "From string S, retrieve the value of N bytes.
+Return the value as an unsigned integer.  The value N must be a
+power of 2, up to 8."
+  (if (= n 8)
+    (let* ((32-bit-parts
+            (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val))
+           (cval (calc-eval '("(2^32 * $ + $$)") nil
+                            (aref 32-bit-parts 0) (aref 32-bit-parts 1))))
+      (when (calc-eval '("$ > $$") 'pred cval most-positive-fixnum)
+        (error "websocket-get-bytes: value too large to parse!"))
+      (string-to-int cval))
+    ;; n is not 8
+    (bindat-get-field (bindat-unpack
+                     `((:val
+                        ,(cond ((= n 1) 'u8)
+                               ((= n 2) 'u16)
+                               ((= n 4) 'u32)
+                               (t (error
+                                   "websocket-get-bytes: Unknown N: %s" n)))))
+                     s) :val)))
 
 (defun websocket-get-opcode (s)
   "Retrieve the opcode from the dword at the start of the frame
 given by string."
-  (let ((opcode (websocket-get-bits (websocket-get-dword s) 4 7)))
+  (let ((opcode (logand #xf (websocket-get-bytes s 1))))
     (cond ((= opcode 0) 'continuation)
           ((= opcode 1) 'text)
           ((= opcode 2) 'binary)
@@ -108,22 +112,12 @@ given by string."
   "Parses out the payload length from the string.
 We start at position 0, and return a cons of the payload length and how
 many bytes were consumed from the string."
-  (let* ((dword (websocket-get-dword s))
-         (initial-val (websocket-get-bits dword 9 15)))
+  (let* ((initial-val (logand 127 (websocket-get-bytes s 1))))
     (cond ((< initial-val 126)
-           (cons initial-val 0))
+           (cons initial-val 1))
           ((= initial-val 126)
-           (cons
-            (bindat-get-field (bindat-unpack '((:val u16)) (substring s 4)) 
:val)
-            3))
-          (t (let* ((32-bit-parts
-                     (bindat-get-field (bindat-unpack '((:val vec 2 u32))
-                                                      (substring s 4)) :val))
-                   (cval (calc-eval "(2^32 * $ + $$)" nil
-                                    (aref 32-bit-parts 0) (aref 32-bit-parts 
1))))
-              (when (calc-eval "$ > $$" 'pred cval most-positive-fixnum)
-                (error "Websocket sent a frame too large for emacs!"))
-              (cons (string-to-int cval) 9))))))
+           (cons (websocket-get-bytes (substring s 1) 2) 3))
+          (t (cons (websocket-get-bytes (substring s 1) 8) 9)))))
 
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.

commit a7ec985d7f592ff0010908d5b6957e0d345577a3
Author: Dmitry Gutov <address@hidden>
Date:   Fri May 18 00:20:45 2012 +0400

    (js2-imenu-record-hashes): Don't walk the node when `end-p`

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
index 7620110..6ee293b 100644
--- a/js2-imenu-extras.el
+++ b/js2-imenu-extras.el
@@ -109,17 +109,18 @@ in a shared namespace."
   (js2-visit-ast
    root
    (lambda (node end-p)
-     (if (and (js2-object-prop-node-p node)
-              (js2-function-node-p (js2-object-prop-node-right node)))
-         (let ((fn-node (js2-object-prop-node-right node)))
-           (unless (and js2-imenu-function-map
-                        (gethash fn-node js2-imenu-function-map))
-             (let ((key-node (js2-object-prop-node-left node)))
-               (js2-record-imenu-entry fn-node
-                                       (list js2-imenu-other-functions-ns
-                                             (js2-prop-node-name key-node))
-                                       (js2-node-abs-pos key-node))))
-           nil)
-       t))))
+     (unless end-p
+       (if (and (js2-object-prop-node-p node)
+                (js2-function-node-p (js2-object-prop-node-right node)))
+           (let ((fn-node (js2-object-prop-node-right node)))
+             (unless (and js2-imenu-function-map
+                          (gethash fn-node js2-imenu-function-map))
+               (let ((key-node (js2-object-prop-node-left node)))
+                 (js2-record-imenu-entry fn-node
+                                         (list js2-imenu-other-functions-ns
+                                               (js2-prop-node-name key-node))
+                                         (js2-node-abs-pos key-node))))
+             nil)
+         t)))))
 
 (provide 'js2-imenu-extras)

commit 8aea7fb84b49983f1d544c1d1d6134f7ed930bab
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 17 23:48:43 2012 +0400

    Implement imenu support for some frameworks and orphan functions
    
    Refs #27
    Refs #38

diff --git a/js2-imenu-extras.el b/js2-imenu-extras.el
new file mode 100644
index 0000000..7620110
--- /dev/null
+++ b/js2-imenu-extras.el
@@ -0,0 +1,125 @@
+(eval-when-compile
+  (require 'cl))
+
+(defconst js2-imenu-extension-styles
+  `((:framework jquery
+     :call-re   "\\_<\\(?:jQuery\\|\\$\\|_\\)\\.extend\\s-*("
+     :recorder  js2-imenu-record-jquery-extend)
+
+    (:framework jquery-ui
+     :call-re   "^\\s-*\\(?:jQuery\\|\\$\\)\\.widget\\s-*("
+     :recorder  js2-imenu-record-string-declare)
+
+    (:framework dojo
+     :call-re   "^\\s-*dojo.declare\\s-*("
+     :recorder  js2-imenu-record-string-declare)
+
+    (:framework backbone
+     :call-re   ,(concat "\\_<" js2-mode-identifier-re "\\.extend\\s-*(")
+     :recorder  js2-imenu-record-backbone-extend)))
+
+(defconst js2-imenu-available-frameworks
+  (mapcar (lambda (style) (plist-get style :framework)) 
js2-imenu-extension-styles)
+  "List of available JavaScript framework symbols.")
+
+(defcustom js2-imenu-enabled-frameworks js2-imenu-available-frameworks
+  "Frameworks to be recognized by `js2-mode'."
+  :type (cons 'set (mapcar (lambda (x) (list 'const x))
+                           js2-imenu-available-frameworks))
+  :group 'js2-mode)
+
+(defcustom js2-imenu-show-other-functions t
+  "Non-nil to show functions not recognized by other mechanisms,
+in a shared namespace."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-imenu-other-functions-ns "?"
+  "Namespace name to use for other functions."
+  :type 'string
+  :group 'js2-mode)
+
+(defun js2-imenu-extras-setup ()
+  (when js2-imenu-enabled-frameworks
+    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-declarations t))
+  (when js2-imenu-show-other-functions
+    (add-to-list 'js2-post-parse-callbacks 'js2-imenu-record-hashes t)))
+
+(declare (special root))
+
+(defun js2-imenu-record-declarations ()
+  (let* ((styles (loop for style in js2-imenu-extension-styles
+                       when (memq (plist-get style :framework)
+                                  js2-imenu-enabled-frameworks)
+                       collect style))
+         (re (mapconcat (lambda (style)
+                          (concat "\\(" (plist-get style :call-re) "\\)"))
+                        styles "\\|"))
+         ;; Dynamic scoping. Ew.
+         (js2-mode-ast root)
+         chains)
+    (goto-char (point-min))
+    (while (js-re-search-forward re nil t)
+      (push (loop for i from 0 to (1- (length styles))
+                  when (match-beginning (1+ i))
+                  return (funcall (plist-get (nth i styles) :recorder)))
+            chains))
+    chains))
+
+(defun js2-imenu-record-jquery-extend ()
+  (let ((pred (lambda (subject)
+                (and
+                 (js2-prop-get-node-p subject)
+                 (string= (js2-name-node-name (js2-prop-get-node-right 
subject))
+                          "prototype")))))
+    (js2-imenu-record-extend-first-arg (1- (point)) pred
+                                       'js2-compute-nested-prop-get)))
+
+(defun js2-imenu-record-string-declare ()
+  (js2-imenu-record-extend-first-arg
+   (1- (point)) 'js2-string-node-p
+   (lambda (node) (split-string (js2-string-node-value node) "\\." t))))
+
+(defun js2-imenu-record-extend-first-arg (point pred qname-fn)
+  (let* ((node (js2-node-at-point point))
+         (args (js2-call-node-args node))
+         (subject (first args)))
+    (when (funcall pred subject)
+      (loop for arg in (cdr args)
+            when (js2-object-node-p arg)
+            do (js2-record-object-literal
+                arg (funcall qname-fn subject) (js2-node-abs-pos arg))))))
+
+(defun js2-imenu-record-backbone-extend ()
+  (let* ((node (js2-node-at-point (1- (point))))
+         (args (js2-call-node-args node))
+         (methods (first args))
+         (parent (js2-node-parent node)))
+    (when (js2-object-node-p methods)
+      (let ((subject (cond ((js2-var-init-node-p parent)
+                            (js2-var-init-node-target parent))
+                           ((js2-assign-node-p parent)
+                            (js2-assign-node-left parent)))))
+        (when subject
+          (js2-record-object-literal methods
+                                     (js2-compute-nested-prop-get subject)
+                                     (js2-node-abs-pos methods)))))))
+
+(defun js2-imenu-record-hashes ()
+  (js2-visit-ast
+   root
+   (lambda (node end-p)
+     (if (and (js2-object-prop-node-p node)
+              (js2-function-node-p (js2-object-prop-node-right node)))
+         (let ((fn-node (js2-object-prop-node-right node)))
+           (unless (and js2-imenu-function-map
+                        (gethash fn-node js2-imenu-function-map))
+             (let ((key-node (js2-object-prop-node-left node)))
+               (js2-record-imenu-entry fn-node
+                                       (list js2-imenu-other-functions-ns
+                                             (js2-prop-node-name key-node))
+                                       (js2-node-abs-pos key-node))))
+           nil)
+       t))))
+
+(provide 'js2-imenu-extras)

commit 7b31606884c0de70d07920ae5f2c3e93f7e5d5ff
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 17 23:47:55 2012 +0400

    Support chains with string elements in `js2-imenu-recorder`

diff --git a/js2-mode.el b/js2-mode.el
index 04522fa..f61b558 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6942,9 +6942,9 @@ For instance, processing a nested scope requires a parent 
function node."
     (dolist (entry entries)
       ;; function node goes first
       (destructuring-bind (current-fn &rest (&whole chain head &rest)) entry
-        ;; examine its defining scope;
-        ;; if top-level/external, keep as-is
-        (if (js2-node-top-level-decl-p head)
+        ;; Examine head's defining scope:
+        ;; Pre-processed chain, or top-level/external, keep as-is.
+        (if (or (stringp head) (js2-node-top-level-decl-p head))
             (push chain result)
           (when (js2-this-node-p head)
             (setq chain (cdr chain))) ; discard this-node

commit 4a77ef03f76b169dabb6040cb0a20a5159e00f8c
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 17 00:47:50 2012 -0400

    Remove tests that no longer pass, and will need to be written.
    
    Also remove the ert-run-tests-interactively, which causes an infinite
    loop on eval-buffer.

diff --git a/websocket-test.el b/websocket-test.el
index d0e5935..8decc26 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -43,39 +43,6 @@
   (loop repeat 100
         do (should (= (string-bytes (websocket-genbytes)) 16))))
 
-(ert-deftest websocket-filter-basic ()
-  (should (equal
-           '("foo")
-           (websocket-test-get-filtered-response '("\0foo\377"))))
-  (should (equal
-           '("foo" "bar")
-           (websocket-test-get-filtered-response
-            '("\0foo\377\0bar\377"))))
-  (should (equal
-           '("foo" "bar")
-           (websocket-test-get-filtered-response
-            '("\0foo\377" "\0bar\377")))))
-
-(ert-deftest websocket-filter-inflight-packets ()
-  (should (equal
-           '("foo" "bar")
-           (websocket-test-get-filtered-response
-            '("\0foo\377\0b" "a" "r\377"))))
-  (should (equal
-           '("foo" "bar")
-           (websocket-test-get-filtered-response
-            '("\0foo\377\0ba" "r\377baz")))))
-
-(ert-deftest websocket-filter-first-response ()
-  (should (equal
-           '("foo" "bar")
-           (websocket-test-get-filtered-response
-            '("HTTP 1.1\0foo\377\0bar\377"))))
-  (should (equal
-           '("foo")
-           (websocket-test-get-filtered-response
-            '("HTTP 1.1" "\0foo\377")))))
-
 (ert-deftest websocket-calculate-accept ()
   ;; This example comes straight from RFC 6455
   (should
@@ -115,9 +82,3 @@
                   (bindat-pack '((:len u32) (:val vec 2 u32))
                                `((:len . ,(lsh 127 16))
                                  (:val . [0 70000])))))))
-
-(ert-run-tests-interactively 'websocket-genbytes-length)
-(ert-run-tests-interactively 'websocket-filter-basic)
-(ert-run-tests-interactively 'websocket-filter-inflight-packets)
-(ert-run-tests-interactively 'websocket-filter-first-response)
-(ert-run-tests-interactively 'websocket-calculate-accept)

commit f4e1aa871bfe35983a989734804251d551785e59
Author: Andrew Hyatt <address@hidden>
Date:   Thu May 17 00:46:23 2012 -0400

    Add helper functions for websocket-get-opcode and
    websocket-get-payload-len.  This is just the first version, and these
    functions probably will need to be rewritten to work with a stream
    that may not yet have all the data.

diff --git a/websocket-test.el b/websocket-test.el
index eb27538..d0e5935 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -94,6 +94,28 @@
     ;; 16-20 = 10110
     (should (equal 22 (websocket-get-bits test-num 16 20)))))
 
+(defconst websocket-test-hello "\x81\x05\x48\x65\x6c\x6c\x6f"
+  "'Hello' string example, taken from the RFC.")
+
+(ert-deftest websocket-get-opcode ()
+  (should (equal 'text (websocket-get-opcode websocket-test-hello))))
+
+(ert-deftest websocket-get-payload-len ()
+  (should (equal '(5 . 0)
+                 (websocket-get-payload-len websocket-test-hello)))
+  (should (equal '(200 . 3)
+                 (websocket-get-payload-len
+                  (bindat-pack '((:len u32) (:val u16))
+                               `((:len . ,(lsh 126 16))
+                                 (:val . 200))))))
+  ;; we don't want to hit up any limits even on strange emacs builds,
+  ;; so this test has a pretty small test value
+  (should (equal '(70000 . 9)
+                 (websocket-get-payload-len
+                  (bindat-pack '((:len u32) (:val vec 2 u32))
+                               `((:len . ,(lsh 127 16))
+                                 (:val . [0 70000])))))))
+
 (ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)
 (ert-run-tests-interactively 'websocket-filter-inflight-packets)
diff --git a/websocket.el b/websocket.el
index a63bd44..0e8d4f2 100644
--- a/websocket.el
+++ b/websocket.el
@@ -24,6 +24,7 @@
 ;; This implements RFC 6455, which can be found at
 ;; http://tools.ietf.org/html/rfc6455.
 
+(require 'bindat)
 (require 'url-parse)
 (require 'calc)
 (eval-when-compile (require 'cl))
@@ -74,8 +75,8 @@ This is based on the KEY from the Sec-WebSocket-Key header."
   (base64-encode-string
    (sha1 (concat key websocket-guid) nil nil t)))
 
-(defun websocket-get-bits (num start-bit end-bit)
-  "Return the value of NUM between START-BIT and END-BIT.
+(defun websocket-get-bits (dword start-bit end-bit)
+  "Return the value of DWORD between START-BIT and END-BIT.
 START-BIT must be less than END-BIT.  The range is inclusive at
 both ends.  Although the ordering of bits is big-endian the bits
 are numbed most significant first.  That is, the most
@@ -83,11 +84,47 @@ significant, leftmost bit is 0."
   (when (> start-bit end-bit)
       (error
        "In websocket-get-bits: Start bit must be less than end-bit."))
-  (logand (lsh num (- (- 31 end-bit)))
+  (logand (lsh dword (- (- 31 end-bit)))
           (loop for i from 0 upto
                 (- end-bit start-bit)
                 sum (expt 2 i))))
 
+(defun websocket-get-dword (s)
+  "From string S, retrieve the first dword."
+  (bindat-get-field (bindat-unpack '((:val dword)) s) :val))
+
+(defun websocket-get-opcode (s)
+  "Retrieve the opcode from the dword at the start of the frame
+given by string."
+  (let ((opcode (websocket-get-bits (websocket-get-dword s) 4 7)))
+    (cond ((= opcode 0) 'continuation)
+          ((= opcode 1) 'text)
+          ((= opcode 2) 'binary)
+          ((= opcode 8) 'close)
+          ((= opcode 9) 'ping)
+          ((= opcode 10) 'pong))))
+
+(defun websocket-get-payload-len (s)
+  "Parses out the payload length from the string.
+We start at position 0, and return a cons of the payload length and how
+many bytes were consumed from the string."
+  (let* ((dword (websocket-get-dword s))
+         (initial-val (websocket-get-bits dword 9 15)))
+    (cond ((< initial-val 126)
+           (cons initial-val 0))
+          ((= initial-val 126)
+           (cons
+            (bindat-get-field (bindat-unpack '((:val u16)) (substring s 4)) 
:val)
+            3))
+          (t (let* ((32-bit-parts
+                     (bindat-get-field (bindat-unpack '((:val vec 2 u32))
+                                                      (substring s 4)) :val))
+                   (cval (calc-eval "(2^32 * $ + $$)" nil
+                                    (aref 32-bit-parts 0) (aref 32-bit-parts 
1))))
+              (when (calc-eval "$ > $$" 'pred cval most-positive-fixnum)
+                (error "Websocket sent a frame too large for emacs!"))
+              (cons (string-to-int cval) 9))))))
+
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
 Websocket packets are sent as the only argument to FILTER, and if

commit be618dad3b73a64a70e89a27ca731d2466d7fbce
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 15 00:38:26 2012 +0400

    Customize the position of '+' for concatenation
    
    Refs #23

diff --git a/js2-mode.el b/js2-mode.el
index 0af9421..a2c6b7b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -306,9 +306,10 @@ If `js2-dynamic-idle-timer-adjust' is 0 or negative,
   :group 'js2-mode)
 
 (defcustom js2-concat-multiline-strings t
-  "Non-nil to automatically turn a newline in mid-string
-into a string concatenation."
-  :type 'boolean
+  "Non-nil to automatically turn a newline in mid-string into a
+string concatenation.  When `eol', the '+' will be inserted at the
+end of the line, otherwise, at the beginning of the next line."
+  :type '(choice (const t) (const eol) (const nil))
   :group 'js2-mode)
 
 (defcustom js2-mode-squeeze-spaces t
@@ -10787,6 +10788,7 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
          (quote-char (nth 3 parse-status))
          (quote-string (string quote-char))
          (string-beg (nth 8 parse-status))
+         (at-eol (eq js2-concat-multiline-strings 'eol))
          (indent (save-match-data
                    (or
                     (save-excursion
@@ -10798,9 +10800,15 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
                       (if (looking-back "\\+\\s-+")
                           (goto-char (match-beginning 0)))
                       (current-column))))))
-    (insert quote-char "\n")
+    (insert quote-char)
+    (if at-eol
+        (insert " +\n")
+      (insert "\n"))
+    ;; FIXME: This does not match the behavior of `js2-indent-line'.
     (indent-to indent)
-    (insert "+ " quote-string)
+    (unless at-eol
+      (insert "+ "))
+    (insert quote-string)
     (when (eolp)
       (insert quote-string)
       (backward-char 1))))

commit b5d4b0324f56754fc340d08681ee1b9e176af98b
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 14 14:10:34 2012 +0200

    Add test case for error handling in filter
    
    Check with another error type.

diff --git a/websocket-test.el b/websocket-test.el
index bf490d4..39c919a 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -99,6 +99,12 @@
     (should (equal err-list nil)))
   (destructuring-bind (packet-data err-list)
       (websocket-test-get-filtered-response-with-error
+       '("\0foo\377\0bar\377")
+       (lambda () "Raise another type of error" (/ 1 0)))
+    (should (equal packet-data '("foo" "bar")))
+    (should (equal err-list nil)))
+  (destructuring-bind (packet-data err-list)
+      (websocket-test-get-filtered-response-with-error
        '("\0foo\377" "\0bar\377")
        (lambda () (error "See if websocket can handle this")))
     (should (equal packet-data '("foo" "bar")))

commit c05e318d03308fa8eb7dbfa83533d342ad1530bd
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 14 14:09:37 2012 +0200

    Improve test for error handling
    
    This way, ERT UI shows what is in err-list so it helps debugging.

diff --git a/websocket-test.el b/websocket-test.el
index d960614..bf490d4 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -96,13 +96,13 @@
        '("\0foo\377\0bar\377")
        (lambda () (error "See if websocket can handle this")))
     (should (equal packet-data '("foo" "bar")))
-    (should (eq (length err-list) 0)))
+    (should (equal err-list nil)))
   (destructuring-bind (packet-data err-list)
       (websocket-test-get-filtered-response-with-error
        '("\0foo\377" "\0bar\377")
        (lambda () (error "See if websocket can handle this")))
     (should (equal packet-data '("foo" "bar")))
-    (should (eq (length err-list) 0))))
+    (should (equal err-list nil))))
 
 (ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)

commit 5614c2ed8f64d646a250d553b016db2f220cc38e
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 14 14:07:43 2012 +0200

    Add error messaging and document error handling

diff --git a/websocket.el b/websocket.el
index c74761b..84e9672 100644
--- a/websocket.el
+++ b/websocket.el
@@ -50,6 +50,9 @@ Best set in a LET statement around the `websocket-open' 
reply.")
 The buffer is ` *websocket URL debug*' where URL is the
 URL of the connection.")
 
+(defvar websocket-ignore-error nil
+  "Set to true to suppress error messages.")
+
 (defun websocket-genbytes ()
   "Generate bytes used at the end of the handshake."
   (let ((s "        "))
@@ -83,7 +86,12 @@ URL of the connection.")
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
 Websocket packets are sent as the only argument to FILTER, and if
-the connection is closed, then CLOSE-CALLBACK is called."
+the connection is closed, then CLOSE-CALLBACK is called.
+Errors from FILTER function will be ignored.  You should catch it in the
+FILTER function in order to recover from the error.  Errors will be
+messaged using `messsage' function.  To suppress messaging errors, set
+`websocket-ignore-error' to `t'.  You can log errors by setting
+`websocket-debug' to `t'."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
          (key1-cons (websocket-genkey))
@@ -144,6 +152,12 @@ the connection is closed, then CLOSE-CALLBACK is called."
   (get-buffer-create (format " *websocket %s debug*"
                              (websocket-url websocket))))
 
+(defun websocket-error (websocket msg &rest args)
+  "Message error."
+  (unless websocket-ignore-error
+    (apply 'message msg args))
+  (apply 'websocket-debug msg args))
+
 (defun websocket-debug (websocket msg &rest args)
   "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
   (when websocket-debug
@@ -165,9 +179,12 @@ the connection is closed, then CLOSE-CALLBACK is called."
     (while (and start-point
                 (setq end-point
                       (string-match "\377" text start-point)))
-      (ignore-errors
-        (funcall (websocket-filter websocket)
-                 (substring text (+ 1 start-point) end-point)))
+      (condition-case err
+          (funcall (websocket-filter websocket)
+                   (substring text (+ 1 start-point) end-point))
+        (error (websocket-error websocket
+                                "Got error from the filter function: %s"
+                                (error-message-string err))))
       (setq start-point (string-match "\0" text end-point)))
     (let* ((next-start (or start-point
                            (when end-point

commit 1dbf7cec84b5b36cbf7d6477bb87301dd6667722
Author: Takafumi Arakaki <address@hidden>
Date:   Sun May 13 20:33:43 2012 +0200

    Ignore error from user specified filter function
    
    Test websocket-filter-handle-error-in-filter passes now.

diff --git a/websocket.el b/websocket.el
index ff06ac1..c74761b 100644
--- a/websocket.el
+++ b/websocket.el
@@ -165,8 +165,9 @@ the connection is closed, then CLOSE-CALLBACK is called."
     (while (and start-point
                 (setq end-point
                       (string-match "\377" text start-point)))
-      (funcall (websocket-filter websocket)
-               (substring text (+ 1 start-point) end-point))
+      (ignore-errors
+        (funcall (websocket-filter websocket)
+                 (substring text (+ 1 start-point) end-point)))
       (setq start-point (string-match "\0" text end-point)))
     (let* ((next-start (or start-point
                            (when end-point

commit db942589fa0b8c864355f8667858d954bd878037
Author: Takafumi Arakaki <address@hidden>
Date:   Sun May 13 20:31:23 2012 +0200

    Add test for error handling in outer-filter
    
    This test fails as currently there is no error handling in
    `websocket-outer-filter'.

diff --git a/websocket-test.el b/websocket-test.el
index c85ca00..d960614 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -28,17 +28,30 @@
 (require 'websocket)
 (eval-when-compile (require 'cl))
 
-(defun websocket-test-get-filtered-response (outputs)
+(defun websocket-test-get-filtered-response-with-error
+  (outputs &optional callback)
   (let* ((packet-data nil)
          (websocket
           (make-websocket :conn "fake-conn"
-                          :filter (lambda (packet) (push packet packet-data))
+                          :filter (lambda (packet)
+                                    (push packet packet-data)
+                                    (when callback (funcall callback)))
                           :close-callback (lambda (not-called) (assert nil))
                           :url "ws://foo/bar"
-                          :v75 nil)))
+                          :v75 nil))
+         err-list)
     (dolist (output outputs)
-      (websocket-outer-filter websocket output))
-    (nreverse packet-data)))
+      (condition-case err
+          (websocket-outer-filter websocket output)
+        (error (push err err-list))))
+    (list (nreverse packet-data) (nreverse err-list))))
+
+(defun websocket-test-get-filtered-response (outputs)
+  (destructuring-bind (packet-data err-list)
+      (websocket-test-get-filtered-response-with-error outputs)
+    (assert (eq (length err-list) 0))
+    packet-data))
+
 
 (ert-deftest websocket-genbytes-length ()
   (loop repeat 100
@@ -77,7 +90,22 @@
            (websocket-test-get-filtered-response
             '("HTTP 1.1" "\0foo\377")))))
 
+(ert-deftest websocket-filter-handle-error-in-filter ()
+  (destructuring-bind (packet-data err-list)
+      (websocket-test-get-filtered-response-with-error
+       '("\0foo\377\0bar\377")
+       (lambda () (error "See if websocket can handle this")))
+    (should (equal packet-data '("foo" "bar")))
+    (should (eq (length err-list) 0)))
+  (destructuring-bind (packet-data err-list)
+      (websocket-test-get-filtered-response-with-error
+       '("\0foo\377" "\0bar\377")
+       (lambda () (error "See if websocket can handle this")))
+    (should (equal packet-data '("foo" "bar")))
+    (should (eq (length err-list) 0))))
+
 (ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)
 (ert-run-tests-interactively 'websocket-filter-inflight-packets)
 (ert-run-tests-interactively 'websocket-filter-first-response)
+(ert-run-tests-interactively 'websocket-filter-handle-error-in-filter)

commit 281c68476aa3382b8ed964c1839c1b51184ea6db
Author: Takafumi Arakaki <address@hidden>
Date:   Sun May 13 19:45:33 2012 +0200

    Fix websocket-outer-filter indentation

diff --git a/websocket.el b/websocket.el
index 78a0ecf..ff06ac1 100644
--- a/websocket.el
+++ b/websocket.el
@@ -162,21 +162,21 @@ the connection is closed, then CLOSE-CALLBACK is called."
         (end-point 0)
         (text (concat (websocket-inflight-packet websocket) output)))
     (setq start-point (string-match "\0" text))
-      (while (and start-point
-                  (setq end-point
-                        (string-match "\377" text start-point)))
-        (funcall (websocket-filter websocket)
-                 (substring text (+ 1 start-point) end-point))
-        (setq start-point (string-match "\0" text end-point)))
-      (let* ((next-start (or start-point
-                                     (when end-point
-                                       (or (string-match "\0" text end-point)
-                                           (- (length text) 1)))
-                                     0))
-             (next-end (or (string-match "\377" text next-start)
-                            (length text))))
-        (setf (websocket-inflight-packet websocket)
-              (concat (substring text next-start next-end))))))
+    (while (and start-point
+                (setq end-point
+                      (string-match "\377" text start-point)))
+      (funcall (websocket-filter websocket)
+               (substring text (+ 1 start-point) end-point))
+      (setq start-point (string-match "\0" text end-point)))
+    (let* ((next-start (or start-point
+                           (when end-point
+                             (or (string-match "\0" text end-point)
+                                 (- (length text) 1)))
+                           0))
+           (next-end (or (string-match "\377" text next-start)
+                         (length text))))
+      (setf (websocket-inflight-packet websocket)
+            (concat (substring text next-start next-end))))))
 
 (defun websocket-send (websocket text)
   "Send the raw TEXT as a websocket packet."

commit 958c32f5b53d5dad610da7fdb6511c7b78422699
Author: katspaugh <address@hidden>
Date:   Sun May 13 14:08:26 2012 +0400

    make multiline string concatenation optional

diff --git a/js2-mode.el b/js2-mode.el
index c44fbff..0af9421 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -305,6 +305,12 @@ If `js2-dynamic-idle-timer-adjust' is 0 or negative,
   :type 'boolean
   :group 'js2-mode)
 
+(defcustom js2-concat-multiline-strings t
+  "Non-nil to automatically turn a newline in mid-string
+into a string concatenation."
+  :type 'boolean
+  :group 'js2-mode)
+
 (defcustom js2-mode-squeeze-spaces t
   "Non-nil to normalize whitespace when filling in comments.
 Multiple runs of spaces are converted to a single space."
@@ -10760,7 +10766,9 @@ This ensures that the counts and `next-error' are 
correct."
     (cond
      ;; check if we're inside a string
      ((nth 3 parse-status)
-      (js2-mode-split-string parse-status))
+      (if js2-concat-multiline-strings
+          (js2-mode-split-string parse-status)
+        (insert "\n")))
      ;; check if inside a block comment
      ((nth 4 parse-status)
       (js2-mode-extend-comment))

commit 416c9e42a06cbfaf098d97446cf75321aff3aba2
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 13 07:34:48 2012 +0400

    Fix typo

diff --git a/js2-mode.el b/js2-mode.el
index 331a9c6..04522fa 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6875,7 +6875,7 @@ we append the property name to QNAME, then call 
`js2-record-imenu-entry'."
                                      (+ pos (js2-node-pos right)))))))))
 
 (defun js2-record-assign-functions (init target)
-  "Record the functions involved in the assigment for imenu.
+  "Record the functions involved in the assignment for imenu.
 TARGET is the target node, INIT is the value node."
   (cond
    ((or (js2-object-node-p init)

commit aafc6ffbebec389052ec540aa3d6620772719cf1
Author: Dmitry Gutov <address@hidden>
Date:   Sun May 13 06:15:11 2012 +0400

    Basic support for module pattern

diff --git a/js2-mode.el b/js2-mode.el
index c44fbff..331a9c6 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6874,6 +6874,34 @@ we append the property name to QNAME, then call 
`js2-record-imenu-entry'."
                                      (append qname (list (js2-infix-node-left 
e)))
                                      (+ pos (js2-node-pos right)))))))))
 
+(defun js2-record-assign-functions (init target)
+  "Record the functions involved in the assigment for imenu.
+TARGET is the target node, INIT is the value node."
+  (cond
+   ((or (js2-object-node-p init)
+        (js2-function-node-p init))
+    (js2-record-imenu-functions init target))
+   ((js2-call-node-p init)
+    ;; Module pattern: var foobs = (function(a) {return {fib: fun...}})(b);
+    ;; We record the returned hash as belonging to the named module, and prefix
+    ;; any functions defined inside IIFE with the module name.
+    (let ((callt (js2-call-node-target init)))
+      ;; Just basic call form: (function() {...})();
+      ;; TODO: Handle variations without duplicating `js2-wrapper-function-p'?
+      (when (and (js2-paren-node-p callt)
+                 (js2-function-node-p (js2-paren-node-expr callt)))
+        (let* ((fn (js2-paren-node-expr callt))
+               (blk (js2-function-node-body fn))
+               (ret (car (last (js2-block-node-kids blk)))))
+          (when (and (js2-return-node-p ret)
+                     (js2-object-node-p (js2-return-node-retval ret)))
+            ;; TODO: Map function names when revealing module pattern is used.
+            (let ((retval (js2-return-node-retval ret)))
+              (js2-record-object-literal retval
+                                         (js2-compute-nested-prop-get target)
+                                         (js2-node-abs-pos retval)))
+            (js2-record-imenu-functions fn target))))))))
+
 (defsubst js2-node-top-level-decl-p (node)
   "Return t if NODE's name is defined in the top-level scope.
 Also returns t if NODE's name is not defined in any scope, since it implies
@@ -8492,10 +8520,8 @@ Returns the parsed `js2-var-decl-node' expression node."
       (when (js2-match-token js2-ASSIGN)
         (setq init (js2-parse-assign-expr)
               end (js2-node-end init))
-        (if (and js2-parse-ide-mode
-                 (or (js2-object-node-p init)
-                     (js2-function-node-p init)))
-            (js2-record-imenu-functions init name)))
+        (when js2-parse-ide-mode
+          (js2-record-assign-functions init name)))
       (when name
         (js2-set-face nbeg nend (if (js2-function-node-p init)
                                     'font-lock-function-name-face
@@ -8656,9 +8682,7 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
                                        :right right))
         (when js2-parse-ide-mode
           (js2-highlight-assign-targets pn left right)
-          (if (or (js2-function-node-p right)
-                  (js2-object-node-p right))
-              (js2-record-imenu-functions right left)))
+          (js2-record-assign-functions right left))
         ;; do this last so ide checks above can use absolute positions
         (js2-node-add-children pn left right))
       pn)))

commit 2a1518b5b2cca67cbe139a98a1c26b39f7c6a1cc
Author: Andrew Hyatt <address@hidden>
Date:   Sat May 12 21:31:16 2012 -0400

    Implementation of websocket-get-bits

diff --git a/websocket-test.el b/websocket-test.el
index 42a0ce2..eb27538 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -82,6 +82,18 @@
    (equal "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
     (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
 
+(ert-deftest websocket-get-bits ()
+  ;; 0         1         2         3
+  ;; 01234567890123456789012345678901
+  ;; For testing, let's use this fairly random sequence
+  ;; 01010001000100101011011110010101
+  ;; = 
+  (let ((test-num 1360181141))
+    (should (equal 1 (websocket-get-bits test-num 0 1)))
+    (should (equal 1 (websocket-get-bits test-num 30 31)))
+    ;; 16-20 = 10110
+    (should (equal 22 (websocket-get-bits test-num 16 20)))))
+
 (ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)
 (ert-run-tests-interactively 'websocket-filter-inflight-packets)
diff --git a/websocket.el b/websocket.el
index 7e0fd72..a63bd44 100644
--- a/websocket.el
+++ b/websocket.el
@@ -74,6 +74,20 @@ This is based on the KEY from the Sec-WebSocket-Key header."
   (base64-encode-string
    (sha1 (concat key websocket-guid) nil nil t)))
 
+(defun websocket-get-bits (num start-bit end-bit)
+  "Return the value of NUM between START-BIT and END-BIT.
+START-BIT must be less than END-BIT.  The range is inclusive at
+both ends.  Although the ordering of bits is big-endian the bits
+are numbed most significant first.  That is, the most
+significant, leftmost bit is 0."
+  (when (> start-bit end-bit)
+      (error
+       "In websocket-get-bits: Start bit must be less than end-bit."))
+  (logand (lsh num (- (- 31 end-bit)))
+          (loop for i from 0 upto
+                (- end-bit start-bit)
+                sum (expt 2 i))))
+
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
 Websocket packets are sent as the only argument to FILTER, and if

commit e38e648f87ef071ee34e65cb0a3b065bf4b1be1d
Author: Reuben Thomas <address@hidden>
Date:   Sat May 12 20:41:16 2012 +0100

    Document use of whitespace-mode.

diff --git a/README.md b/README.md
index 07547f6..51a7322 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,15 @@ If `coffee-mode` is not enabled automatically for any files 
ending in
     (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
     (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
 
+[coffee-mode used to offer automatic deletion of trailing whitespace.
+This is now left to whitespace-mode. See its documentation for full
+details, but as a hint, configure:
+
+    (setq whitespace-action '(auto-cleanup)) ;; automatically clean up bad 
whitespace
+    (setq whitespace-style '(trailing space-before-tab indentation empty 
space-after-tab)) ;; only show bad whitespace
+
+Then turn on whitespace-mode, or global-whitespace-mode.]
+
 ## Indentation
 
 ### TAB Theory

commit 83be921a9b84a8f34e6fe90d444557c86f7823e3
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 19:51:35 2012 +0100

    Remove out-of-date information on configuring tab width, and an 
overcomplicated use of coffee-cos-mode.

diff --git a/README.md b/README.md
index f56882a..07547f6 100644
--- a/README.md
+++ b/README.md
@@ -28,26 +28,6 @@ If `coffee-mode` is not enabled automatically for any files 
ending in
 
 ## Indentation
 
-### Configuring
-
-Lines are indented according to the `tab-width` variable. If you're
-like me, you probably have this set in your Emacs config globally:
-
-    (setq-default tab-width 4)
-
-Well, idiomatic CoffeeScript uses two spaces. We can set our
-`tab-width` to two for `coffee-mode` using the `coffee-mode-hook`:
-
-    (defun coffee-custom ()
-      "coffee-mode-hook"
-     (set (make-local-variable 'tab-width) 2))
-
-    (add-hook 'coffee-mode-hook
-      '(lambda() (coffee-custom)))
-
-For more configuration options and another example of this hook, look
-further down in this README.
-
 ### TAB Theory
 
 It goes like this: when you press `TAB`, we indent the line unless
@@ -194,13 +174,6 @@ compile-on-save minor mode in `coffee-mode`.  To enable it 
by default:
 
     (add-hook 'coffee-mode-hook '(lambda () (coffee-cos-mode t)))
 
-To enable it only if it looks like you may want to:
-
-    (add-hook 'coffee-mode-hook '(lambda ()
-                                   (and (file-exists-p (buffer-file-name))
-                                        (file-exists-p 
(coffee-compiled-file-name))
-                                        (coffee-cos-mode t))))
-
 ### coffee-repl
 
 Starts a repl in a new buffer using `coffee-command`.

commit 65797fafd745160b62b64ac2dbbec8c0516efc4e
Author: Jaehyun Yeom <address@hidden>
Date:   Mon Apr 16 21:33:21 2012 +0900

    Fix missing function `some' issue when loading compiled elisp.
    
    Function `some' requires 'cl and it is loaded while compilation only.

diff --git a/coffee-mode.el b/coffee-mode.el
index db0f631..cfa90a4 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -517,10 +517,12 @@ previous line."
         (end-of-line)
 
         ;; Optimized for speed - checks only the last character.
-        (when (some (lambda (char)
-                        (= (char-before) char))
-                      coffee-indenters-eol)
-          (setq indenter-at-eol t)))
+        (let ((indenters coffee-indenters-eol))
+          (while indenters
+            (if (/= (char-before) (car indenters))
+                (setq indenters (cdr indenters))
+              (setq indenter-at-eol t)
+              (setq indenters nil)))))
 
       ;; If we found an indenter, return `t'.
       (or indenter-at-bol indenter-at-eol))))

commit 6d1d92d7802f5908ae3cb0bd85942215de87f060
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 18:29:56 2012 +0100

    Make coffee-mode-hook customizable.

diff --git a/coffee-mode.el b/coffee-mode.el
index e4ca162..db0f631 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -117,8 +117,10 @@ with CoffeeScript."
   :type 'string
   :group 'coffee)
 
-(defvar coffee-mode-hook nil
-  "Hook run when entering `coffee-mode'.")
+(defcustom coffee-mode-hook nil
+  "Hook called by `coffee-mode'."
+  :type 'hook
+  :group 'coffee)
 
 (defvar coffee-mode-map (make-keymap)
   "Keymap for CoffeeScript major mode.")

commit 3f4271f084959bb825754600441fee1bac677268
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 18:16:01 2012 +0100

    Simplify coffee-indent-line and coffee-previous-indent.
    
    As a result, remove coffee-line-as-string and coffee-line-empty-p.

diff --git a/coffee-mode.el b/coffee-mode.el
index dd0e009..e4ca162 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -124,14 +124,6 @@ with CoffeeScript."
   "Keymap for CoffeeScript major mode.")
 
 ;;
-;; Macros
-;;
-
-(defmacro coffee-line-as-string ()
-  "Returns the current line as a string."
-  `(buffer-substring (point-at-bol) (point-at-eol)))
-
-;;
 ;; Commands
 ;;
 
@@ -437,13 +429,8 @@ output in a compilation buffer."
   (if (= (point) (point-at-bol))
       (insert-tab)
     (save-excursion
-      (let ((prev-indent 0) (cur-indent 0))
-        ;; Figure out the indentation of the previous line
-        (setq prev-indent (coffee-previous-indent))
-
-        ;; Figure out the current line's indentation
-        (setq cur-indent (current-indentation))
-
+      (let ((prev-indent (coffee-previous-indent))
+            (cur-indent (current-indentation)))
         ;; Shift one column to the left
         (beginning-of-line)
         (insert-tab)
@@ -463,14 +450,9 @@ output in a compilation buffer."
     (if (bobp)
         0
       (progn
-        (while (and (coffee-line-empty-p) (not (bobp))) (forward-line -1))
+        (while (and (looking-at "^[ \t]*$") (not (bobp))) (forward-line -1))
         (current-indentation)))))
 
-(defun coffee-line-empty-p ()
-  "Is this line empty? Returns non-nil if so, nil if not."
-  (or (bobp)
-   (string-match "^\\s *$" (coffee-line-as-string))))
-
 (defun coffee-newline-and-indent ()
   "Insert a newline and indent it to the same level as the previous line."
   (interactive)

commit 39dd8a3a967ee9ea2188a36115b22ad052e97321
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 10 05:17:33 2012 +0400

    Fix #46
    
    * Check if "for" is inside comment
    * Don't indent array comprehensions when language version < 1.7

diff --git a/js2-mode.el b/js2-mode.el
index 73c9608..c44fbff 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10003,8 +10003,9 @@ In particular, return the buffer position of the first 
`for' kwd."
             ;; so we'll just guess at it.
             (if (and (> end (point)) ; not empty literal
                      (re-search-forward "[^,]]* \\(for\\) " end t)
-                     ;; not inside a string literal
-                     (not (nth 3 (parse-partial-sexp bracket (point)))))
+                     ;; not inside comment or string literal
+                     (let ((state (parse-partial-sexp bracket (point))))
+                       (not (or (nth 3 state) (nth 4 state)))))
                 (match-beginning 1))))))))
 
 (defun js2-array-comp-indentation (parse-status for-kwd)
@@ -10033,6 +10034,7 @@ In particular, return the buffer position of the first 
`for' kwd."
       (cond
        ;; indent array comprehension continuation lines specially
        ((and bracket
+             (>= js2-language-version 170)
              (not (js2-same-line bracket))
              (setq beg (js2-indent-in-array-comp parse-status))
              (>= (point) (save-excursion

commit 07050bcc310ddf7c85fc63b751c0a4a07c7e236d
Author: Andrew Hyatt <address@hidden>
Date:   Tue May 8 23:59:48 2012 -0400

    Get opening handshake to work correctly.  Framing does not yet work,
    and because of this the handshake test does also not happen yet.

diff --git a/testserver.py b/testserver.py
index c402853..5cfcb96 100644
--- a/testserver.py
+++ b/testserver.py
@@ -19,7 +19,7 @@ class EchoWebSocket(websocket.WebSocketHandler):
         logging.info("ON_CLOSE")
 
     def allow_draft76(self):
-        return True
+        return False
 
 
 if __name__ == "__main__":
diff --git a/websocket-test.el b/websocket-test.el
index f498b96..42a0ce2 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -41,7 +41,7 @@
 
 (ert-deftest websocket-genbytes-length ()
   (loop repeat 100
-        do (should (= (string-bytes (websocket-genbytes)) 8))))
+        do (should (= (string-bytes (websocket-genbytes)) 16))))
 
 (ert-deftest websocket-filter-basic ()
   (should (equal
diff --git a/websocket.el b/websocket.el
index c362e7f..7e0fd72 100644
--- a/websocket.el
+++ b/websocket.el
@@ -34,6 +34,8 @@
   (filter (assert nil) :read-only t)
   (close-callback (assert nil) :read-only t)
   (url (assert nil) :read-only t)
+  (accept-string (assert nil))
+  (handshake-accept-passed-p nil)
   (inflight-packet nil))
 
 (defvar websocket-debug nil
@@ -45,10 +47,14 @@ URL of the connection.")
   "The websocket GUID as defined in RFC 6455. Do not change
   unless the RFC changes.")
 
+(defvar websocket-require-server-accept t
+  "If true, we require the correct Sec-WebSocket-Accept header
+as part of the connection handshake.")
+
 (defun websocket-genbytes ()
   "Generate bytes used at the end of the handshake."
-  (let ((s "        "))
-    (dotimes (i 8)
+  (let ((s "                "))
+    (dotimes (i 16)
       (aset s i (random 256)))
     s))
 
@@ -60,20 +66,7 @@ URL of the connection.")
 
 (defun websocket-genkey ()
   "Generate a key suitable for the websocket handshake."
-  (let* ((num-spaces (+ 1 (random 12)))
-         (max-num-str (calc-eval (format "floor(random(4294967295 / %d)) * %d"
-                                         num-spaces num-spaces)))
-         (num max-num-str))
-    (dotimes (_ num-spaces)
-      (setq max-num-str (websocket-random-insert " " max-num-str)))
-    (dotimes (_ (+ 1 (random 12)))
-      (setq max-num-str (websocket-random-insert
-                         (let ((r (random 82)))
-                           (char-to-string
-                            (if (< r 15) (+ 33 r)
-                               (+ 58 (- r 15)))))
-                         max-num-str)))
-    (cons max-num-str num)))
+  (base64-encode-string (websocket-genbytes)))
 
 (defun websocket-calculate-accept (key)
   "Calculate the expect value of the accept header.
@@ -87,9 +80,7 @@ Websocket packets are sent as the only argument to FILTER, 
and if
 the connection is closed, then CLOSE-CALLBACK is called."
   (let* ((name (format "websocket to %s" url))
          (url-struct (url-generic-parse-url url))
-         (key1-cons (websocket-genkey))
-         (key2-cons (websocket-genkey))
-         (bytes (websocket-genbytes))
+         (key (websocket-genkey))
          (buf-name (format " *%s*" name))
          (coding-system-for-read 'binary)
          (coding-system-for-write 'binary)
@@ -103,7 +94,9 @@ the connection is closed, then CLOSE-CALLBACK is called."
                      (error "Not implemented yet")
                    (error "Unknown protocol"))))
          (websocket (make-websocket :conn conn :url url :filter filter
-                                    :close-callback close-callback)))
+                                    :close-callback close-callback
+                                    :accept-string
+                                    (websocket-calculate-accept key))))
     (lexical-let ((websocket websocket))
       (set-process-filter conn
                           (lambda (process output)
@@ -124,19 +117,16 @@ the connection is closed, then CLOSE-CALLBACK is called."
     (websocket-debug websocket "Sending handshake")
     (process-send-string
      conn
-     (format (concat "Upgrade: WebSocket\r\n"
+     (format (concat "Host: %s\r\n"
+                     "Upgrade: websocket\r\n"
                      "Connection: Upgrade\r\n"
-                     "Host: %s\r\n"
+                     "Sec-WebSocket-Key: %s\r\n"
                      "Origin: %s\r\n"
-                     "Sec-WebSocket-Key1: %s\r\n"
-                     "Sec-WebSocket-Key2: %s\r\n"
+                     "Sec-WebSocket-Version: 13\r\n"
                      "\r\n")
              (url-host (url-generic-parse-url url))
              system-name
-             (car key1-cons)
-             (car key2-cons)))
-    (websocket-debug websocket "Sending bytes")
-    (process-send-string conn bytes)
+             key))
     (websocket-debug websocket "Websocket opened")
     websocket))
 
@@ -162,9 +152,22 @@ the connection is closed, then CLOSE-CALLBACK is called."
         (end-point 0)
         (text (concat (websocket-inflight-packet websocket) output)))
     (setq start-point (string-match "\0" text))
-      (while (and start-point
-                  (setq end-point
-                        (string-match "\377" text start-point)))
+    ;; If we've received the first packet, check to see if we've
+    ;; received the desired handshake.
+    (when (and websocket-require-server-accept
+               (not (websocket-handshake-accept-passed-p websocket))
+               start-point)
+      (let ((accept-string
+             (concat "Sec-WebSocket-Accept: " (websocket-accept-string 
websocket))))
+        (websocket-debug websocket "Handshake received, checking for: %s" 
accept-string)
+        (if (string-match (regexp-quote accept-string) text)
+            (progn
+              (setf (websocket-handshake-accept-passed-p websocket) t)
+              (websocket-debug websocket "Handshake accepted"))
+        (error "Incorrect handshake from websocket: is this really a websocket 
connection?"))))
+    (while (and start-point
+                (setq end-point
+                      (string-match "\377" text start-point)))
         (funcall (websocket-filter websocket)
                  (substring text (+ 1 start-point) end-point))
         (setq start-point (string-match "\0" text end-point)))

commit 579e270cf98d4cbd6a37f5469274143e73acea90
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 18:04:35 2012 +0100

    Overhaul the docstrings.
    
    Rename coffee-show-version to coffee-version for consistency with
    other modes.
    
    Fix a minor instance of odd code layout.

diff --git a/coffee-mode.el b/coffee-mode.el
index c0dad1a..dd0e009 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -67,7 +67,7 @@
 ;;
 
 (defconst coffee-mode-version "0.4.1"
-  "The version of this `coffee-mode'.")
+  "The version of `coffee-mode'.")
 
 (defgroup coffee nil
   "A CoffeeScript major mode."
@@ -79,30 +79,27 @@
   :group 'coffee)
 
 (defcustom coffee-command "coffee"
-  "The CoffeeScript command used for evaluating code. Must be in your
-path."
+  "The CoffeeScript command used for evaluating code."
   :type 'string
   :group 'coffee)
 
 (defcustom js2coffee-command "js2coffee"
-  "The js2coffee command used for evaluating code. Must be in your
-path."
+  "The js2coffee command used for evaluating code."
   :type 'string
   :group 'coffee)
 
-
 (defcustom coffee-args-repl '("-i")
-  "The command line arguments to pass to `coffee-command' to start a REPL."
+  "The arguments to pass to `coffee-command' to start a REPL."
   :type 'list
   :group 'coffee)
 
 (defcustom coffee-args-compile '("-c")
-  "The command line arguments to pass to `coffee-command' when compiling a 
file."
+  "The arguments to pass to `coffee-command' to compile a file."
   :type 'list
   :group 'coffee)
 
 (defcustom coffee-compiled-buffer-name "*coffee-compiled*"
-  "The name of the scratch buffer used when compiling CoffeeScript."
+  "The name of the scratch buffer used for compiled CoffeeScript."
   :type 'string
   :group 'coffee)
 
@@ -110,17 +107,18 @@ path."
   "Whether to jump to the first error if compilation fails.
 Please note that the coffee compiler doesn't always give a line
 number for the issue and in that case it is not possible to jump
-to the error, of course."
+to the error."
   :type 'boolean
   :group 'coffee)
 
 (defcustom coffee-watch-buffer-name "*coffee-watch*"
-  "The name of the scratch buffer used when using the --watch flag with  
CoffeeScript."
+  "The name of the scratch buffer used when using the --watch flag
+with CoffeeScript."
   :type 'string
   :group 'coffee)
 
 (defvar coffee-mode-hook nil
-  "A hook for you to run your own code when the mode is loaded.")
+  "Hook run when entering `coffee-mode'.")
 
 (defvar coffee-mode-map (make-keymap)
   "Keymap for CoffeeScript major mode.")
@@ -154,7 +152,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (concat (file-name-sans-extension (or filename (buffer-file-name))) ".js"))
 
 (defun coffee-compile-file ()
-  "Compiles and saves the current file to disk. Doesn't open in a buffer.."
+  "Compiles and saves the current file to disk."
   (interactive)
   (let ((compiler-output (shell-command-to-string (coffee-command-compile 
(buffer-file-name)))))
     (if (string= compiler-output "")
@@ -168,13 +166,15 @@ If FILENAME is omitted, the current buffer's file name is 
used."
           (forward-line (1- line)))))))
 
 (defun coffee-compile-buffer ()
-  "Compiles the current buffer and displays the JS in another buffer."
+  "Compiles the current buffer and displays the JavaScript in a buffer
+called `coffee-compiled-buffer-name'."
   (interactive)
   (save-excursion
     (coffee-compile-region (point-min) (point-max))))
 
 (defun coffee-compile-region (start end)
-  "Compiles a region and displays the JS in another buffer."
+  "Compiles a region and displays the JavaScript in a buffer called
+`coffee-compiled-buffer-name'."
   (interactive "r")
 
   (let ((buffer (get-buffer coffee-compiled-buffer-name)))
@@ -190,7 +190,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (goto-char (point-min)))
 
 (defun coffee-js2coffee-replace-region (start end)
-  "Replace JS to coffee in current buffer."
+  "Convert JavaScript in the region into CoffeeScript."
   (interactive "r")
 
   (let ((buffer (get-buffer coffee-compiled-buffer-name)))
@@ -199,18 +199,16 @@ If FILENAME is omitted, the current buffer's file name is 
used."
 
   (call-process-region start end
                        js2coffee-command nil
-                       (current-buffer)
-                       )
-  (delete-region start end)
-  )
+                       (current-buffer))
+  (delete-region start end))
 
-(defun coffee-show-version ()
-  "Prints the `coffee-mode' version."
+(defun coffee-version ()
+  "Show the `coffee-mode' version in the echo area."
   (interactive)
-  (message (concat "coffee-mode v" coffee-mode-version)))
+  (message (concat "coffee-mode version " coffee-mode-version)))
 
 (defun coffee-watch (dir-or-file)
-  "Run `coffee-run-cmd' with the --watch flag enabled for a directory or file"
+  "Run `coffee-run-cmd' with the --watch flag on a directory or file."
   (interactive "fDirectory or File: ")
   (let ((coffee-compiled-buffer-name coffee-watch-buffer-name)
         (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(expand-file-name dir-or-file))) " ")))
@@ -305,19 +303,20 @@ If FILENAME is omitted, the current buffer's file name is 
used."
 
 (defun coffee-comment-dwim (arg)
   "Comment or uncomment current line or region in a smart way.
-For detail, see `comment-dwim'."
+For details, see `comment-dwim'."
   (interactive "*P")
   (require 'newcomment)
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
 (defun coffee-command-compile (file-name)
-  "The `coffee-command' with args to compile a file."
+  "Run `coffee-command' to compile FILE."
   (let ((full-file-name (expand-file-name file-name)))
     (mapconcat 'identity (append (list coffee-command) coffee-args-compile 
(list full-file-name)) " ")))
 
 (defun coffee-run-cmd (args)
-  "Given an arbitrary set of arguments for the `coffee-command', compile the 
command and show output in a custom compilation buffer."
+  "Run `coffee-command' with the given arguments, and display the
+output in a compilation buffer."
   (interactive "sArguments: ")
   (let ((compilation-buffer-name-function (lambda (this-mode)
                                             (generate-new-buffer-name 
coffee-compiled-buffer-name))))
@@ -459,7 +458,6 @@ For detail, see `comment-dwim'."
 
 (defun coffee-previous-indent ()
   "Return the indentation level of the previous non-blank line."
-
   (save-excursion
     (forward-line -1)
     (if (bobp)
@@ -474,7 +472,7 @@ For detail, see `comment-dwim'."
    (string-match "^\\s *$" (coffee-line-as-string))))
 
 (defun coffee-newline-and-indent ()
-  "Inserts a newline and indents it to the same level as the previous line."
+  "Insert a newline and indent it to the same level as the previous line."
   (interactive)
 
   ;; Remember the current line indentation level,
@@ -513,8 +511,8 @@ next line should probably be indented.")
 should probably be indented.")
 
 (defun coffee-line-wants-indent ()
-  "Does the current line want to be indented deeper than the previous
-line? Returns `t' or `nil'. See the README for more details."
+  "Return t if the current line should be indented relative to the
+previous line."
   (interactive)
 
   (save-excursion
@@ -544,13 +542,13 @@ line? Returns `t' or `nil'. See the README for more 
details."
       (or indenter-at-bol indenter-at-eol))))
 
 (defun coffee-previous-line-is-comment ()
-  "Returns `t' if the previous line is a CoffeeScript comment."
+  "Return t if the previous line is a CoffeeScript comment."
   (save-excursion
     (forward-line -1)
     (coffee-line-is-comment)))
 
 (defun coffee-line-is-comment ()
-  "Returns `t' if the current line is a CoffeeScript comment."
+  "Return t if the current line is a CoffeeScript comment."
   (save-excursion
     (backward-to-indentation 0)
     (= (char-after) (string-to-char "#"))))

commit f687d8cc0b507c1553d215bb7ae7d7185ca127f8
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 17:45:25 2012 +0100

    Use mode configured for .js files for compiled JS buffers.

diff --git a/README.md b/README.md
index 7c65a08..f56882a 100644
--- a/README.md
+++ b/README.md
@@ -172,8 +172,7 @@ line, so you can investigate.  If this annoys you, you can 
set
 
 Compiles the current buffer to JavaScript using the command specified
 by the `coffee-command` variable and opens the contents in a new
-buffer using your JavaScript mode of choice. The JavaScript mode is
-determined by the `coffee-js-mode` variable and defaults to `js2-mode`.
+buffer using the mode configured for ".js" files.
 
 Bind it:
 
@@ -219,9 +218,6 @@ Naturally. Example:
       (make-local-variable 'tab-width)
       (set 'tab-width 2)
 
-      ;; If you don't have js2-mode
-      (setq coffee-js-mode 'javascript-mode)
-
       ;; If you don't want your compiled files to be wrapped
       (setq coffee-args-compile '("-c" "--bare"))
 
@@ -246,12 +242,6 @@ customize-group` with "coffee" as the group.
 You can also customize then with `coffee-mode-hook`, as demonstrated
 above.
 
-### coffee-js-mode
-
-The mode to use when viewing compiled JavaScript.
-
-Default: `'js2-mode`
-
 ### coffee-tab-width
 
 The tab width to use when indenting.
diff --git a/coffee-mode.el b/coffee-mode.el
index b1910c9..c0dad1a 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -73,11 +73,6 @@
   "A CoffeeScript major mode."
   :group 'languages)
 
-(defcustom coffee-js-mode 'js2-mode
-  "The mode to use when viewing compiled JavaScript."
-  :type 'string
-  :group 'coffee)
-
 (defcustom coffee-tab-width tab-width
   "The tab width to use when indenting."
   :type 'integer
@@ -191,7 +186,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
                           nil)
          (append coffee-args-compile (list "-s" "-p")))
   (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
-  (funcall coffee-js-mode)
+  (let ((buffer-file-name) "tmp.js") (set-auto-mode))
   (goto-char (point-min)))
 
 (defun coffee-js2coffee-replace-region (start end)

commit 5703337fca7018662b5df528c492bd76392fa363
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 16:55:40 2012 +0100

    Simplify bug reporting section of README.md.

diff --git a/README.md b/README.md
index bfc9b73..7c65a08 100644
--- a/README.md
+++ b/README.md
@@ -305,13 +305,7 @@ Default: `t`
 Prototype accessor assignments like `String::length: -> 10` don't look
 great.
 
-It's tested on Aquamacs 1.9 (Emacs 22) for OS X Snow Leopard so it may
-not work on your environment. Please file a bug at
-<http://github.com/defunkt/coffee-mode/issues> and maybe we can fix
-the problem.
-
-This is the author's first major mode, so there are probably more
-bugs.
+Please file bugs at <http://github.com/defunkt/coffee-mode/issues>
 
 [cs]: http://jashkenas.github.com/coffee-script/
 [tm]: http://github.com/defunkt/textmate.el

commit 8bb36ac818bac352b19761698a670a3dbe551e44
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 16:41:43 2012 +0100

    Remove apply-partially, which is available in Emacs 23 and later.

diff --git a/coffee-mode.el b/coffee-mode.el
index 32b4866..b1910c9 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -131,20 +131,6 @@ to the error, of course."
   "Keymap for CoffeeScript major mode.")
 
 ;;
-;; Compat
-;;
-
-(unless (fboundp 'apply-partially)
-  (defun apply-partially (fun &rest args)
-    "Return a function that is a partial application of FUN to ARGS.
-ARGS is a list of the first N arguments to pass to FUN.
-The result is a new function which does the same as FUN, except that
-the first N arguments are fixed at the values with which this function
-was called."
-    (lexical-let ((fun fun) (args1 args))
-      (lambda (&rest args2) (apply fun (append args1 args2))))))
-
-;;
 ;; Macros
 ;;
 

commit 5b957dde1236b05e3db9956310b08152892f52b8
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 16:21:07 2012 +0100

    Remove functions that merely open reference URLs.
    
    Emacs has bookmark management tools.

diff --git a/coffee-mode.el b/coffee-mode.el
index 4f1a03f..32b4866 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -228,21 +228,6 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (interactive)
   (message (concat "coffee-mode v" coffee-mode-version)))
 
-(defun coffee-open-reference ()
-  "Open browser to CoffeeScript reference."
-  (interactive)
-  (browse-url "http://jashkenas.github.com/coffee-script/";))
-
-(defun coffee-open-node-reference ()
-  "Open browser to node.js documentation."
-  (interactive)
-  (browse-url "http://nodejs.org/docs/";))
-
-(defun coffee-open-github ()
-  "Open browser to `coffee-mode' project on GithHub."
-  (interactive)
-  (browse-url "http://github.com/defunkt/coffee-mode";))
-
 (defun coffee-watch (dir-or-file)
   "Run `coffee-run-cmd' with the --watch flag enabled for a directory or file"
   (interactive "fDirectory or File: ")
@@ -262,9 +247,6 @@ If FILENAME is omitted, the current buffer's file name is 
used."
     ["Compile Region" coffee-compile-region]
     ["REPL" coffee-repl]
     "---"
-    ["CoffeeScript Reference" coffee-open-reference]
-    ["node.js Reference" coffee-open-node-reference]
-    ["coffee-mode on GitHub" coffee-open-github]
     ["Version" coffee-show-version]
     ))
 

commit 89203e8ed0f4b57c45035dbb6ab9c1c54e732841
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 16:16:44 2012 +0100

    Make version consistent and bump it to 0.4.1 (Fixes #61).

diff --git a/coffee-mode.el b/coffee-mode.el
index eaa9f4f..4f1a03f 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010 Chris Wanstrath
 
-;; Version: 0.4.0
+;; Version: 0.4.1
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
 ;; URL: http://github.com/defunkt/coffee-mode
@@ -66,7 +66,7 @@
 ;; Customizable Variables
 ;;
 
-(defconst coffee-mode-version "0.3.0"
+(defconst coffee-mode-version "0.4.1"
   "The version of this `coffee-mode'.")
 
 (defgroup coffee nil

commit 66c326b6fef15a3cb17ce1290bcf39bd0a8dd1fc
Author: Reuben Thomas <address@hidden>
Date:   Tue May 8 16:13:33 2012 +0100

    Remove custom debug code; should use the standard Emacs debugging tools 
instead.

diff --git a/README.md b/README.md
index 42829cd..bfc9b73 100644
--- a/README.md
+++ b/README.md
@@ -225,9 +225,6 @@ Naturally. Example:
       ;; If you don't want your compiled files to be wrapped
       (setq coffee-args-compile '("-c" "--bare"))
 
-      ;; *Messages* spam
-      (setq coffee-debug-mode t)
-
       ;; Emacs key binding
       (define-key coffee-mode-map [(meta r)] 'coffee-compile-buffer)
 
@@ -249,12 +246,6 @@ customize-group` with "coffee" as the group.
 You can also customize then with `coffee-mode-hook`, as demonstrated
 above.
 
-### coffee-debug-mode
-
-Whether to run in debug mode or not. Logs to `*Messages*`.
-
-Default: `t`
-
 ### coffee-js-mode
 
 The mode to use when viewing compiled JavaScript.
diff --git a/coffee-mode.el b/coffee-mode.el
index b2baaaa..eaa9f4f 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -73,11 +73,6 @@
   "A CoffeeScript major mode."
   :group 'languages)
 
-(defcustom coffee-debug-mode nil
-  "Whether to run in debug mode or not. Logs to `*Messages*'."
-  :type 'boolean
-  :group 'coffee-mode)
-
 (defcustom coffee-js-mode 'js2-mode
   "The mode to use when viewing compiled JavaScript."
   :type 'string
@@ -111,16 +106,6 @@ path."
   :type 'list
   :group 'coffee)
 
-(defcustom coffee-cygwin-mode t
-  "For Windows systems, add support for Cygwin-style absolute paths."
-  :type 'boolean
-  :group 'coffee)
-
-(defcustom coffee-cygwin-prefix "/cygdrive/C"
-  "The prefix with which to replace the drive-letter for your Windows 
partition, e.g. 'C:' would be replaced by '/c/cygdrive'."
-  :type 'string
-  :group 'coffee)
-
 (defcustom coffee-compiled-buffer-name "*coffee-compiled*"
   "The name of the scratch buffer used when compiling CoffeeScript."
   :type 'string
@@ -163,19 +148,6 @@ was called."
 ;; Macros
 ;;
 
-(defmacro setd (var val)
-  "Like setq but optionally logs the variable's value using `coffee-debug'."
-  (if (and (boundp 'coffee-debug-mode) coffee-debug-mode)
-      `(progn
-         (coffee-debug "%s: %s" ',var ,val)
-         (setq ,var ,val))
-    `(setq ,var ,val)))
-
-(defun coffee-debug (string &rest args)
-  "Print a message when in debug mode."
-  (when coffee-debug-mode
-      (apply 'message (append (list string) args))))
-
 (defmacro coffee-line-as-string ()
   "Returns the current line as a string."
   `(buffer-substring (point-at-bol) (point-at-eol)))
@@ -207,12 +179,12 @@ If FILENAME is omitted, the current buffer's file name is 
used."
     (if (string= compiler-output "")
         (message "Compiled and saved %s" (coffee-compiled-file-name))
       (let* ((msg (car (split-string compiler-output "[\n\r]+")))
-            (line (and (string-match "on line \\([0-9]+\\)" msg)
-                       (string-to-number (match-string 1 msg)))))
-       (message msg)
-       (when (and coffee-compile-jump-to-error line (> line 0))
-         (goto-char (point-min))
-         (forward-line (1- line)))))))
+             (line (and (string-match "on line \\([0-9]+\\)" msg)
+                        (string-to-number (match-string 1 msg)))))
+        (message msg)
+        (when (and coffee-compile-jump-to-error line (> line 0))
+          (goto-char (point-min))
+          (forward-line (1- line)))))))
 
 (defun coffee-compile-buffer ()
   "Compiles the current buffer and displays the JS in another buffer."
@@ -244,7 +216,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
     (when buffer
       (kill-buffer buffer)))
 
-  (call-process-region start end 
+  (call-process-region start end
                        js2coffee-command nil
                        (current-buffer)
                        )
@@ -275,7 +247,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   "Run `coffee-run-cmd' with the --watch flag enabled for a directory or file"
   (interactive "fDirectory or File: ")
   (let ((coffee-compiled-buffer-name coffee-watch-buffer-name)
-        (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(coffee-universal-path dir-or-file))) " ")))
+        (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(expand-file-name dir-or-file))) " ")))
     (coffee-run-cmd args)))
 
 ;;
@@ -376,21 +348,9 @@ For detail, see `comment-dwim'."
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
-(defun coffee-cygwin-path (expanded-file-name)
-  "Given an expanded file name, derive the absolute Cygwin path based on 
`coffee-cygwin-prefix'."
-  (replace-regexp-in-string "^[a-zA-Z]:" coffee-cygwin-prefix 
expanded-file-name t))
-
-(defun coffee-universal-path (file-name)
-  "Handle different paths for different OS configurations for CoffeeScript"
-  (let ((full-file-name (expand-file-name file-name)))
-    (if (and (equal system-type 'windows-nt)
-             coffee-cygwin-mode)
-        (coffee-cygwin-path full-file-name)
-      full-file-name)))
-
 (defun coffee-command-compile (file-name)
   "The `coffee-command' with args to compile a file."
-  (let ((full-file-name (coffee-universal-path file-name)))
+  (let ((full-file-name (expand-file-name file-name)))
     (mapconcat 'identity (append (list coffee-command) coffee-args-compile 
(list full-file-name)) " ")))
 
 (defun coffee-run-cmd (args)
@@ -462,8 +422,6 @@ For detail, see `comment-dwim'."
             (point-max)
             t)
 
-      (coffee-debug "Match: %s" (match-string 0))
-
       ;; If this is the start of a new namespace, save the namespace's
       ;; indentation level and name.
       (when (match-string 8)
@@ -474,10 +432,7 @@ For detail, see `comment-dwim'."
         (setq ns-name (concat ns-name "::"))
 
         ;; Save the indentation level.
-        (setq ns-indent (length (match-string 1)))
-
-        ;; Debug
-        (coffee-debug "ns: Found %s with indent %s" ns-name ns-indent))
+        (setq ns-indent (length (match-string 1))))
 
       ;; If this is an assignment, save the token being
       ;; assigned. `Please.print:` will be `Please.print`, `block:`
@@ -495,12 +450,9 @@ For detail, see `comment-dwim'."
           (when (and ns-name (> indent ns-indent))
             (setq assign (concat ns-name assign)))
 
-          (coffee-debug "=: Found %s with indent %s" assign indent)
-
           ;; Clear the namespace if we're no longer indented deeper
           ;; than it.
           (when (and ns-name (<= indent ns-indent))
-            (coffee-debug "ns: Clearing %s" ns-name)
             (setq ns-name nil)
             (setq ns-indent nil))
 
@@ -525,23 +477,18 @@ For detail, see `comment-dwim'."
     (save-excursion
       (let ((prev-indent 0) (cur-indent 0))
         ;; Figure out the indentation of the previous line
-        (setd prev-indent (coffee-previous-indent))
+        (setq prev-indent (coffee-previous-indent))
 
         ;; Figure out the current line's indentation
-        (setd cur-indent (current-indentation))
+        (setq cur-indent (current-indentation))
 
         ;; Shift one column to the left
         (beginning-of-line)
         (insert-tab)
 
-        (coffee-debug "point: %s" (point))
-        (coffee-debug "point-at-bol: %s" (point-at-bol))
-
         (when (= (point-at-bol) (point))
           (forward-char coffee-tab-width))
 
-        (coffee-debug "New indent: %s" (current-indentation))
-
         ;; We're too far, remove all indentation.
         (when (> (- (current-indentation) prev-indent) coffee-tab-width)
           (backward-to-indentation 0)
@@ -616,7 +563,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
       ;; If the next few characters match one of our magic indenter
       ;; keywords, we want to indent the line we were on originally.
       (when (looking-at (coffee-indenters-bol-regexp))
-        (setd indenter-at-bol t))
+        (setq indenter-at-bol t))
 
       ;; If that didn't match, go to the back of the line and check to
       ;; see if the last character matches one of our indenter
@@ -628,7 +575,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
         (when (some (lambda (char)
                         (= (char-before) char))
                       coffee-indenters-eol)
-          (setd indenter-at-eol t)))
+          (setq indenter-at-eol t)))
 
       ;; If we found an indenter, return `t'.
       (or indenter-at-bol indenter-at-eol))))

commit be2305f545f64d0a3c0e5e71876c7b36b935787c
Author: Reuben Thomas <address@hidden>
Date:   Mon May 7 15:50:22 2012 +0100

    Remove support for removing trailing whitespace: whitepace-mode does that.
    
    Fixes #64.

diff --git a/README.md b/README.md
index c7f5834..42829cd 100644
--- a/README.md
+++ b/README.md
@@ -261,12 +261,6 @@ The mode to use when viewing compiled JavaScript.
 
 Default: `'js2-mode`
 
-### coffee-cleanup-whitespace
-
-Should we `delete-trailing-whitespace' on save? Probably.
-
-Default: `t`
-
 ### coffee-tab-width
 
 The tab width to use when indenting.
diff --git a/coffee-mode.el b/coffee-mode.el
index 0f1ec91..b2baaaa 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -83,11 +83,6 @@
   :type 'string
   :group 'coffee)
 
-(defcustom coffee-cleanup-whitespace t
-  "Should we `delete-trailing-whitespace' on save? Probably."
-  :type 'boolean
-  :group 'coffee)
-
 (defcustom coffee-tab-width tab-width
   "The tab width to use when indenting."
   :type 'integer
@@ -373,12 +368,6 @@ If FILENAME is omitted, the current buffer's file name is 
used."
 ;; Helper Functions
 ;;
 
-(defun coffee-before-save ()
-  "Hook run before file is saved. Deletes whitespace if
-`coffee-cleanup-whitespace' is non-nil."
-  (when coffee-cleanup-whitespace
-    (delete-trailing-whitespace)))
-
 (defun coffee-comment-dwim (arg)
   "Comment or uncomment current line or region in a smart way.
 For detail, see `comment-dwim'."
@@ -695,10 +684,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   (setq imenu-create-index-function 'coffee-imenu-create-index)
 
   ;; no tabs
-  (setq indent-tabs-mode nil)
-
-  ;; hooks
-  (set (make-local-variable 'before-save-hook) 'coffee-before-save))
+  (setq indent-tabs-mode nil))
 
 ;;
 ;; Compile-on-Save minor mode

commit b5bbce12dc2dfdc3bcfee13e702b9d99f113b84e
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 23:28:06 2012 -0400

    Add a function to calculate the accept header expected.

diff --git a/websocket-test.el b/websocket-test.el
index e7cdea3..f498b96 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -76,7 +76,14 @@
            (websocket-test-get-filtered-response
             '("HTTP 1.1" "\0foo\377")))))
 
+(ert-deftest websocket-calculate-accept ()
+  ;; This example comes straight from RFC 6455
+  (should
+   (equal "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
+    (websocket-calculate-accept "dGhlIHNhbXBsZSBub25jZQ=="))))
+
 (ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)
 (ert-run-tests-interactively 'websocket-filter-inflight-packets)
 (ert-run-tests-interactively 'websocket-filter-first-response)
+(ert-run-tests-interactively 'websocket-calculate-accept)
diff --git a/websocket.el b/websocket.el
index 1ee2af1..c362e7f 100644
--- a/websocket.el
+++ b/websocket.el
@@ -41,6 +41,10 @@
 The buffer is ` *websocket URL debug*' where URL is the
 URL of the connection.")
 
+(defconst websocket-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+  "The websocket GUID as defined in RFC 6455. Do not change
+  unless the RFC changes.")
+
 (defun websocket-genbytes ()
   "Generate bytes used at the end of the handshake."
   (let ((s "        "))
@@ -71,6 +75,12 @@ URL of the connection.")
                          max-num-str)))
     (cons max-num-str num)))
 
+(defun websocket-calculate-accept (key)
+  "Calculate the expect value of the accept header.
+This is based on the KEY from the Sec-WebSocket-Key header."
+  (base64-encode-string
+   (sha1 (concat key websocket-guid) nil nil t)))
+
 (defun websocket-open (url filter &optional close-callback)
   "Open a websocket connection to URL.
 Websocket packets are sent as the only argument to FILTER, and if

commit 763cb60f33390b1c6f9f09c9186872d7b1906172
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 22:59:05 2012 -0400

    Get rid of all mentions of version 75.

diff --git a/websocket-test.el b/websocket-test.el
index c85ca00..e7cdea3 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -34,8 +34,7 @@
           (make-websocket :conn "fake-conn"
                           :filter (lambda (packet) (push packet packet-data))
                           :close-callback (lambda (not-called) (assert nil))
-                          :url "ws://foo/bar"
-                          :v75 nil)))
+                          :url "ws://foo/bar")))
     (dolist (output outputs)
       (websocket-outer-filter websocket output))
     (nreverse packet-data)))
diff --git a/websocket.el b/websocket.el
index 31fc950..1ee2af1 100644
--- a/websocket.el
+++ b/websocket.el
@@ -34,12 +34,7 @@
   (filter (assert nil) :read-only t)
   (close-callback (assert nil) :read-only t)
   (url (assert nil) :read-only t)
-  (inflight-packet nil)
-  (v75 (assert nil) :read-only t))
-
-(defvar websocket-use-v75 nil
-  "Set to true if to use the older v75 protocol.
-Best set in a LET statement around the `websocket-open' reply.")
+  (inflight-packet nil))
 
 (defvar websocket-debug nil
   "Set to true to output debugging info to a per-websocket buffer.
@@ -98,8 +93,7 @@ the connection is closed, then CLOSE-CALLBACK is called."
                      (error "Not implemented yet")
                    (error "Unknown protocol"))))
          (websocket (make-websocket :conn conn :url url :filter filter
-                                    :close-callback close-callback
-                                    :v75 websocket-use-v75)))
+                                    :close-callback close-callback)))
     (lexical-let ((websocket websocket))
       (set-process-filter conn
                           (lambda (process output)
@@ -132,7 +126,7 @@ the connection is closed, then CLOSE-CALLBACK is called."
              (car key1-cons)
              (car key2-cons)))
     (websocket-debug websocket "Sending bytes")
-    (unless websocket-use-v75 (process-send-string conn bytes))
+    (process-send-string conn bytes)
     (websocket-debug websocket "Websocket opened")
     websocket))
 
@@ -202,10 +196,9 @@ the connection is closed, then CLOSE-CALLBACK is called."
                  ((run open listen) t)
                  ((stop exit signal closed connect failed nil) nil)))
     (websocket-close websocket)
-    (let ((websocket-use-v75 (websocket-v75 websocket)))
-      (websocket-open (websocket-url websocket)
+    (websocket-open (websocket-url websocket)
                       (websocket-filter websocket)
-                      (websocket-close-callback websocket)))))
+                      (websocket-close-callback websocket))))
 
 (provide 'websocket)
 

commit cb7a69f255775ff04c7ae3dd7cf0ad6139c09233
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 22:57:18 2012 -0400

    Claim in the headers that we are implementing RFC 6455.  It isn't true yet, 
but it will be.

diff --git a/websocket.el b/websocket.el
index 78a0ecf..31fc950 100644
--- a/websocket.el
+++ b/websocket.el
@@ -21,12 +21,8 @@
 ;; 02110-1301, USA.
 
 ;;; Commentary:
-;; This implements two version of the websocket protocol, the older
-;; v75 protocol:
-;; http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
-;;
-;; By default, we use the newer v76 protocol:
-;; http://www.whatwg.org/specs/web-socket-protocol/
+;; This implements RFC 6455, which can be found at
+;; http://tools.ietf.org/html/rfc6455.
 
 (require 'url-parse)
 (require 'calc)

commit fbee9504c5407f4a9f3cf6e85cc8d0655a34f0d8
Merge: 799d213 fcc5c9e
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 19:41:21 2012 -0700

    Merge pull request #6 from tkf/functional-test
    
    Add functional testing


commit 799d213bd16d088c3234c7649ce84d8756e14bc7
Merge: 0241173 8105178
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 19:36:37 2012 -0700

    Merge pull request #4 from tkf/websocket-genbytes-length
    
    Fix websocket-genbytes

diff --cc websocket.el
index b4a542d,3979dcb..d0bdc3a
--- a/websocket.el
+++ b/websocket.el
@@@ -50,12 -50,14 +50,12 @@@ Best set in a LET statement around the 
  The buffer is ` *websocket URL debug*' where URL is the
  URL of the connection.")
  
 -(defconst websocket-keylen 20)
 -
  (defun websocket-genbytes ()
    "Generate bytes used at the end of the handshake."
-   (let ((s '()))
-     (dotimes (v 8)
-       (push (random 256) s))
-     (apply 'string s)))
+   (let ((s "        "))
+     (dotimes (i 8)
+       (aset s i (random 256)))
+     s))
  
  (defun websocket-random-insert (str-to-insert target-str)
    "Insert STR-TO-INSERT at a random position in TARGET-STR."

commit 024117368853ea06607cbbc0c9245d18aabf9e20
Merge: 4d81f4f 5599c1b
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 19:34:04 2012 -0700

    Merge pull request #5 from tkf/bunch-of-changes
    
    Bunch of changes


commit fcc5c9eac128c78bb87a4fb84f49cca99305dbf6
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 02:13:53 2012 +0200

    Add wstest-pop-to-debug for debugging

diff --git a/websocket-functional-test.el b/websocket-functional-test.el
index 712a331..e7e849d 100644
--- a/websocket-functional-test.el
+++ b/websocket-functional-test.el
@@ -22,6 +22,11 @@
    (lambda (p) (push p wstest-msgs) (message "ws packet: %S" p))
    (lambda () (setq wstest-closed t))))
 
+(defun wstest-pop-to-debug ()
+  "Open websocket log buffer. Not used in testing. Just for debugging."
+  (interactive)
+  (pop-to-buffer (websocket-get-debug-buffer-create wstest-ws)))
+
 (sleep-for 0.1)
 (assert (websocket-openp wstest-ws))
 

commit 6b8d5347a4f6230c4d907bd585b1f7f2d29771fc
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:49:24 2012 +0200

    Add a function websocket-get-debug-buffer-create

diff --git a/websocket.el b/websocket.el
index d0bdc3a..78a0ecf 100644
--- a/websocket.el
+++ b/websocket.el
@@ -140,11 +140,14 @@ the connection is closed, then CLOSE-CALLBACK is called."
     (websocket-debug websocket "Websocket opened")
     websocket))
 
+(defun websocket-get-debug-buffer-create (websocket)
+  (get-buffer-create (format " *websocket %s debug*"
+                             (websocket-url websocket))))
+
 (defun websocket-debug (websocket msg &rest args)
   "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
   (when websocket-debug
-    (let ((buf (get-buffer-create (format " *websocket %s debug*"
-                                          (websocket-url websocket)))))
+    (let ((buf (websocket-get-debug-buffer-create websocket)))
       (save-excursion
         (with-current-buffer buf
           (goto-char (point-max))

commit fc58f2cd0c67771d31aa7fb3338137e82d5067ae
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 02:05:56 2012 +0200

    Add a simple script for functional testing

diff --git a/testserver.py b/testserver.py
new file mode 100644
index 0000000..c402853
--- /dev/null
+++ b/testserver.py
@@ -0,0 +1,34 @@
+import logging
+import tornado
+import tornado.web
+from tornado import httpserver
+from tornado import ioloop
+from tornado import websocket
+
+
+class EchoWebSocket(websocket.WebSocketHandler):
+
+    def open(self):
+        logging.info("OPEN")
+
+    def on_message(self, message):
+        logging.info(u"ON_MESSAGE: {0}".format(message))
+        self.write_message(u"You said: {0}".format(message))
+
+    def on_close(self):
+        logging.info("ON_CLOSE")
+
+    def allow_draft76(self):
+        return True
+
+
+if __name__ == "__main__":
+    import tornado.options
+    tornado.options.parse_command_line()
+    application = tornado.web.Application([
+        (r"/", EchoWebSocket),
+    ])
+    server = httpserver.HTTPServer(application)
+    server.listen(9999)
+    logging.info("STARTED: Server start listening")
+    ioloop.IOLoop.instance().start()
diff --git a/websocket-functional-test.el b/websocket-functional-test.el
new file mode 100644
index 0000000..712a331
--- /dev/null
+++ b/websocket-functional-test.el
@@ -0,0 +1,36 @@
+;; Simple functional testing
+;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el
+
+(require 'websocket)
+(eval-when-compile (require 'cl))
+
+(setq websocket-debug t)
+
+(defvar wstest-server-buffer (get-buffer-create "*wstest-server*"))
+(defvar wstest-server-name "wstest-server")
+(defvar wstest-server-proc
+  (start-process wstest-server-name wstest-server-buffer
+                 "python" "testserver.py" "--log_to_stderr" "--logging=debug"))
+(sleep-for 1)
+
+(defvar wstest-msgs nil)
+(defvar wstest-closed nil)
+
+(defvar wstest-ws
+  (websocket-open
+   "ws://127.0.0.1:9999"
+   (lambda (p) (push p wstest-msgs) (message "ws packet: %S" p))
+   (lambda () (setq wstest-closed t))))
+
+(sleep-for 0.1)
+(assert (websocket-openp wstest-ws))
+
+(assert (null wstest-msgs))
+(websocket-send wstest-ws "Hi!")
+(sleep-for 0.1)
+(assert (equal (car wstest-msgs) "You said: Hi!"))
+
+(websocket-close wstest-ws)
+(assert (null (websocket-openp wstest-ws)))
+
+(stop-process wstest-server-proc)

commit a4875a92e8066b76cf6c3f2b2214af86b01b2764
Merge: 5599c1b 8105178
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:54:09 2012 +0200

    Merge branch 'websocket-genbytes-length' into tkf

diff --cc websocket.el
index b4a542d,3979dcb..d0bdc3a
--- a/websocket.el
+++ b/websocket.el
@@@ -50,12 -50,14 +50,12 @@@ Best set in a LET statement around the 
  The buffer is ` *websocket URL debug*' where URL is the
  URL of the connection.")
  
 -(defconst websocket-keylen 20)
 -
  (defun websocket-genbytes ()
    "Generate bytes used at the end of the handshake."
-   (let ((s '()))
-     (dotimes (v 8)
-       (push (random 256) s))
-     (apply 'string s)))
+   (let ((s "        "))
+     (dotimes (i 8)
+       (aset s i (random 256)))
+     s))
  
  (defun websocket-random-insert (str-to-insert target-str)
    "Insert STR-TO-INSERT at a random position in TARGET-STR."

commit 5599c1b25e196e53a79dc1c5a48eadf06a4babb5
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:48:43 2012 +0200

    Refactor websocket-open
    
    * Header string is split in short strings so that code fits in
      narrower width screen.
    * Header and the last handshake bytes is separated.
    * Two additional debug messages are added.

diff --git a/websocket.el b/websocket.el
index 4c03d68..b4a542d 100644
--- a/websocket.el
+++ b/websocket.el
@@ -121,13 +121,22 @@ the connection is closed, then CLOSE-CALLBACK is called."
                          (format "GET %s HTTP/1.1\r\n"
                                  (let ((path (url-filename url-struct)))
                                    (if (> (length path) 0) path "/"))))
-    (process-send-string conn
-                         (format "Upgrade: WebSocket\r\nConnection: 
Upgrade\r\nHost: %s\r\nOrigin: %s\r\nSec-WebSocket-Key1: 
%s\r\nSec-WebSocket-Key2: %s\r\n\r\n%s"
-                                 (url-host (url-generic-parse-url url))
-                                 system-name
-                                 (car key1-cons)
-                                 (car key2-cons)
-                                 (if websocket-use-v75 ""  bytes)))
+    (websocket-debug websocket "Sending handshake")
+    (process-send-string
+     conn
+     (format (concat "Upgrade: WebSocket\r\n"
+                     "Connection: Upgrade\r\n"
+                     "Host: %s\r\n"
+                     "Origin: %s\r\n"
+                     "Sec-WebSocket-Key1: %s\r\n"
+                     "Sec-WebSocket-Key2: %s\r\n"
+                     "\r\n")
+             (url-host (url-generic-parse-url url))
+             system-name
+             (car key1-cons)
+             (car key2-cons)))
+    (websocket-debug websocket "Sending bytes")
+    (unless websocket-use-v75 (process-send-string conn bytes))
     (websocket-debug websocket "Websocket opened")
     websocket))
 

commit fed3408332db3915a943c157e5e37fd9e54a43d0
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:44:05 2012 +0200

    Add [WS] prefix to debug message
    
    This is useful when showing multiline message.

diff --git a/websocket.el b/websocket.el
index 27dac90..4c03d68 100644
--- a/websocket.el
+++ b/websocket.el
@@ -139,6 +139,7 @@ the connection is closed, then CLOSE-CALLBACK is called."
       (save-excursion
         (with-current-buffer buf
           (goto-char (point-max))
+          (insert "[WS] ")
           (insert (apply 'format (append (list msg) args)))
           (insert "\n"))))))
 

commit e65d0e9fa52234351373c894a86ac0cb6e921ded
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:42:18 2012 +0200

    No confirmation when closing websocket buffer

diff --git a/websocket.el b/websocket.el
index 65bb78c..27dac90 100644
--- a/websocket.el
+++ b/websocket.el
@@ -116,6 +116,7 @@ the connection is closed, then CLOSE-CALLBACK is called."
                                 (unless (websocket-openp websocket)
                                   (funcall (websocket-close-callback
                                             websocket)))))))
+    (set-process-query-on-exit-flag conn nil)
     (process-send-string conn
                          (format "GET %s HTTP/1.1\r\n"
                                  (let ((path (url-filename url-struct)))

commit 60b977edee66beb23feac8bec0fda143c3c0e77e
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:41:03 2012 +0200

    Remove unused variable websocket-keylen

diff --git a/websocket.el b/websocket.el
index a621ea0..65bb78c 100644
--- a/websocket.el
+++ b/websocket.el
@@ -50,8 +50,6 @@ Best set in a LET statement around the `websocket-open' 
reply.")
 The buffer is ` *websocket URL debug*' where URL is the
 URL of the connection.")
 
-(defconst websocket-keylen 20)
-
 (defun websocket-genbytes ()
   "Generate bytes used at the end of the handshake."
   (let ((s '()))

commit c859f29a9d7a993a417552f58dec236f73f6fea2
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:40:32 2012 +0200

    Fix header comment

diff --git a/websocket.el b/websocket.el
index 99bb606..a621ea0 100644
--- a/websocket.el
+++ b/websocket.el
@@ -1,4 +1,4 @@
-;;; wave-client-websocket.el --- Methods to communicate with the Wave server
+;;; websocket.el --- Emacs WebSocket client
 
 ;; Copyright (c) 2010 Andrew Hyatt
 ;;

commit 810517800ae5d78c9c76f7d5e04f15ba2cdc975b
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:28:55 2012 +0200

    Fix websocket-genbytes
    
    It passes the test websocket-genbytes-length now.

diff --git a/websocket.el b/websocket.el
index 99bb606..3979dcb 100644
--- a/websocket.el
+++ b/websocket.el
@@ -54,10 +54,10 @@ URL of the connection.")
 
 (defun websocket-genbytes ()
   "Generate bytes used at the end of the handshake."
-  (let ((s '()))
-    (dotimes (v 8)
-      (push (random 256) s))
-    (apply 'string s)))
+  (let ((s "        "))
+    (dotimes (i 8)
+      (aset s i (random 256)))
+    s))
 
 (defun websocket-random-insert (str-to-insert target-str)
   "Insert STR-TO-INSERT at a random position in TARGET-STR."

commit 45245a4699b527e06e36e9b21c2234d458d9461b
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:26:14 2012 +0200

    Add test websocket-genbytes-length
    
    This test fails in Emacs 24.1.50.1.

diff --git a/websocket-test.el b/websocket-test.el
index beac0fd..c85ca00 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -40,6 +40,10 @@
       (websocket-outer-filter websocket output))
     (nreverse packet-data)))
 
+(ert-deftest websocket-genbytes-length ()
+  (loop repeat 100
+        do (should (= (string-bytes (websocket-genbytes)) 8))))
+
 (ert-deftest websocket-filter-basic ()
   (should (equal
            '("foo")
@@ -73,6 +77,7 @@
            (websocket-test-get-filtered-response
             '("HTTP 1.1" "\0foo\377")))))
 
+(ert-run-tests-interactively 'websocket-genbytes-length)
 (ert-run-tests-interactively 'websocket-filter-basic)
 (ert-run-tests-interactively 'websocket-filter-inflight-packets)
 (ert-run-tests-interactively 'websocket-filter-first-response)

commit 9d8794aa2315025950f479f71501de6c3b2e06fd
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 01:13:52 2012 +0200

    Suppress compilation warning in websocket-test.el

diff --git a/websocket-test.el b/websocket-test.el
index 5b935de..beac0fd 100644
--- a/websocket-test.el
+++ b/websocket-test.el
@@ -25,16 +25,17 @@
 ;; http://github.com/ohler/ert, it also comes with Emacs 24 and above.
 
 (require 'ert)
-(require 'cl)
+(require 'websocket)
+(eval-when-compile (require 'cl))
 
 (defun websocket-test-get-filtered-response (outputs)
-  (let ((packet-data nil)
-        (websocket
-         (make-websocket :conn "fake-conn"
-                         :filter (lambda (packet) (push packet packet-data))
-                         :close-callback (lambda (not-called) (assert nil))
-                         :url "ws://foo/bar"
-                         :v75 nil)))
+  (let* ((packet-data nil)
+         (websocket
+          (make-websocket :conn "fake-conn"
+                          :filter (lambda (packet) (push packet packet-data))
+                          :close-callback (lambda (not-called) (assert nil))
+                          :url "ws://foo/bar"
+                          :v75 nil)))
     (dolist (output outputs)
       (websocket-outer-filter websocket output))
     (nreverse packet-data)))

commit 4d81f4f693d74d0f5dc3375f12871701a8c1f2f7
Author: Takafumi Arakaki <address@hidden>
Date:   Mon May 7 00:59:20 2012 +0200

    Do not require cl package at runtime
    
    Fix #2.

diff --git a/websocket.el b/websocket.el
index b46ba70..99bb606 100644
--- a/websocket.el
+++ b/websocket.el
@@ -30,7 +30,7 @@
 
 (require 'url-parse)
 (require 'calc)
-(require 'cl)
+(eval-when-compile (require 'cl))
 
 ;;; Code:
 (defstruct websocket

commit 59697b40cb9d1d76bedabd89411dcc1192c967c2
Author: Andrew Hyatt <address@hidden>
Date:   Sun May 6 17:06:18 2012 -0400

    Initial checkin of files.  These files were initially part of the
    emacs client for Wave project (now defunct), located at
    http://code.google.com/p/wave-client-for-emacs/.
    
    I've changed the license to be GPL.

diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..ecbc059
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
\ No newline at end of file
diff --git a/websocket-test.el b/websocket-test.el
new file mode 100644
index 0000000..5b935de
--- /dev/null
+++ b/websocket-test.el
@@ -0,0 +1,77 @@
+;;; websocket-test.el --- Unit tests for the websocket layer
+
+;; Copyright (c) 2010 Andrew Hyatt
+;;
+;; Author: Andrew Hyatt <ahyatt at gmail dot com>
+;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;;; Commentary:
+;; This defines and runs ert unit tests.  You can download ert from:
+;; http://github.com/ohler/ert, it also comes with Emacs 24 and above.
+
+(require 'ert)
+(require 'cl)
+
+(defun websocket-test-get-filtered-response (outputs)
+  (let ((packet-data nil)
+        (websocket
+         (make-websocket :conn "fake-conn"
+                         :filter (lambda (packet) (push packet packet-data))
+                         :close-callback (lambda (not-called) (assert nil))
+                         :url "ws://foo/bar"
+                         :v75 nil)))
+    (dolist (output outputs)
+      (websocket-outer-filter websocket output))
+    (nreverse packet-data)))
+
+(ert-deftest websocket-filter-basic ()
+  (should (equal
+           '("foo")
+           (websocket-test-get-filtered-response '("\0foo\377"))))
+  (should (equal
+           '("foo" "bar")
+           (websocket-test-get-filtered-response
+            '("\0foo\377\0bar\377"))))
+  (should (equal
+           '("foo" "bar")
+           (websocket-test-get-filtered-response
+            '("\0foo\377" "\0bar\377")))))
+
+(ert-deftest websocket-filter-inflight-packets ()
+  (should (equal
+           '("foo" "bar")
+           (websocket-test-get-filtered-response
+            '("\0foo\377\0b" "a" "r\377"))))
+  (should (equal
+           '("foo" "bar")
+           (websocket-test-get-filtered-response
+            '("\0foo\377\0ba" "r\377baz")))))
+
+(ert-deftest websocket-filter-first-response ()
+  (should (equal
+           '("foo" "bar")
+           (websocket-test-get-filtered-response
+            '("HTTP 1.1\0foo\377\0bar\377"))))
+  (should (equal
+           '("foo")
+           (websocket-test-get-filtered-response
+            '("HTTP 1.1" "\0foo\377")))))
+
+(ert-run-tests-interactively 'websocket-filter-basic)
+(ert-run-tests-interactively 'websocket-filter-inflight-packets)
+(ert-run-tests-interactively 'websocket-filter-first-response)
diff --git a/websocket.el b/websocket.el
new file mode 100644
index 0000000..b46ba70
--- /dev/null
+++ b/websocket.el
@@ -0,0 +1,204 @@
+;;; wave-client-websocket.el --- Methods to communicate with the Wave server
+
+;; Copyright (c) 2010 Andrew Hyatt
+;;
+;; Author: Andrew Hyatt <ahyatt at gmail dot com>
+;; Maintainer: Andrew Hyatt <ahyatt at gmail dot com>
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
+
+;;; Commentary:
+;; This implements two version of the websocket protocol, the older
+;; v75 protocol:
+;; http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
+;;
+;; By default, we use the newer v76 protocol:
+;; http://www.whatwg.org/specs/web-socket-protocol/
+
+(require 'url-parse)
+(require 'calc)
+(require 'cl)
+
+;;; Code:
+(defstruct websocket
+  (conn (assert nil) :read-only t)
+  (filter (assert nil) :read-only t)
+  (close-callback (assert nil) :read-only t)
+  (url (assert nil) :read-only t)
+  (inflight-packet nil)
+  (v75 (assert nil) :read-only t))
+
+(defvar websocket-use-v75 nil
+  "Set to true if to use the older v75 protocol.
+Best set in a LET statement around the `websocket-open' reply.")
+
+(defvar websocket-debug nil
+  "Set to true to output debugging info to a per-websocket buffer.
+The buffer is ` *websocket URL debug*' where URL is the
+URL of the connection.")
+
+(defconst websocket-keylen 20)
+
+(defun websocket-genbytes ()
+  "Generate bytes used at the end of the handshake."
+  (let ((s '()))
+    (dotimes (v 8)
+      (push (random 256) s))
+    (apply 'string s)))
+
+(defun websocket-random-insert (str-to-insert target-str)
+  "Insert STR-TO-INSERT at a random position in TARGET-STR."
+  (let ((r (+ 1 (random (- (length target-str) 2)))))
+    (concat (substring target-str 0 r) str-to-insert
+            (substring target-str r))))
+
+(defun websocket-genkey ()
+  "Generate a key suitable for the websocket handshake."
+  (let* ((num-spaces (+ 1 (random 12)))
+         (max-num-str (calc-eval (format "floor(random(4294967295 / %d)) * %d"
+                                         num-spaces num-spaces)))
+         (num max-num-str))
+    (dotimes (_ num-spaces)
+      (setq max-num-str (websocket-random-insert " " max-num-str)))
+    (dotimes (_ (+ 1 (random 12)))
+      (setq max-num-str (websocket-random-insert
+                         (let ((r (random 82)))
+                           (char-to-string
+                            (if (< r 15) (+ 33 r)
+                               (+ 58 (- r 15)))))
+                         max-num-str)))
+    (cons max-num-str num)))
+
+(defun websocket-open (url filter &optional close-callback)
+  "Open a websocket connection to URL.
+Websocket packets are sent as the only argument to FILTER, and if
+the connection is closed, then CLOSE-CALLBACK is called."
+  (let* ((name (format "websocket to %s" url))
+         (url-struct (url-generic-parse-url url))
+         (key1-cons (websocket-genkey))
+         (key2-cons (websocket-genkey))
+         (bytes (websocket-genbytes))
+         (buf-name (format " *%s*" name))
+         (coding-system-for-read 'binary)
+         (coding-system-for-write 'binary)
+         (conn (if (equal (url-type url-struct) "ws")
+                   (make-network-process :name name
+                                         :buffer buf-name
+                                         :host (url-host url-struct)
+                                         :service (url-port url-struct)
+                                         :nowait nil)
+                 (if (equal (url-type url-struct) "wss")
+                     (error "Not implemented yet")
+                   (error "Unknown protocol"))))
+         (websocket (make-websocket :conn conn :url url :filter filter
+                                    :close-callback close-callback
+                                    :v75 websocket-use-v75)))
+    (lexical-let ((websocket websocket))
+      (set-process-filter conn
+                          (lambda (process output)
+                            (websocket-outer-filter websocket output)))
+      (when close-callback
+        (set-process-sentinel conn
+                              (lambda (process change)
+                                (websocket-debug websocket
+                                                 "State change to %s" change)
+                                (unless (websocket-openp websocket)
+                                  (funcall (websocket-close-callback
+                                            websocket)))))))
+    (process-send-string conn
+                         (format "GET %s HTTP/1.1\r\n"
+                                 (let ((path (url-filename url-struct)))
+                                   (if (> (length path) 0) path "/"))))
+    (process-send-string conn
+                         (format "Upgrade: WebSocket\r\nConnection: 
Upgrade\r\nHost: %s\r\nOrigin: %s\r\nSec-WebSocket-Key1: 
%s\r\nSec-WebSocket-Key2: %s\r\n\r\n%s"
+                                 (url-host (url-generic-parse-url url))
+                                 system-name
+                                 (car key1-cons)
+                                 (car key2-cons)
+                                 (if websocket-use-v75 ""  bytes)))
+    (websocket-debug websocket "Websocket opened")
+    websocket))
+
+(defun websocket-debug (websocket msg &rest args)
+  "In the WEBSOCKET's debug buffer, send MSG, with format ARGS."
+  (when websocket-debug
+    (let ((buf (get-buffer-create (format " *websocket %s debug*"
+                                          (websocket-url websocket)))))
+      (save-excursion
+        (with-current-buffer buf
+          (goto-char (point-max))
+          (insert (apply 'format (append (list msg) args)))
+          (insert "\n"))))))
+
+(defun websocket-outer-filter (websocket output)
+  "Removes connection strings, only passes packets."
+  (websocket-debug websocket "Received: %s" output)
+  (let ((start-point 0)
+        (end-point 0)
+        (text (concat (websocket-inflight-packet websocket) output)))
+    (setq start-point (string-match "\0" text))
+      (while (and start-point
+                  (setq end-point
+                        (string-match "\377" text start-point)))
+        (funcall (websocket-filter websocket)
+                 (substring text (+ 1 start-point) end-point))
+        (setq start-point (string-match "\0" text end-point)))
+      (let* ((next-start (or start-point
+                                     (when end-point
+                                       (or (string-match "\0" text end-point)
+                                           (- (length text) 1)))
+                                     0))
+             (next-end (or (string-match "\377" text next-start)
+                            (length text))))
+        (setf (websocket-inflight-packet websocket)
+              (concat (substring text next-start next-end))))))
+
+(defun websocket-send (websocket text)
+  "Send the raw TEXT as a websocket packet."
+  (websocket-debug websocket "Sending text: %s" text)
+  (websocket-ensure-connected websocket)
+  (unless (websocket-openp websocket)
+    (error "No webserver process to send data to!"))
+  (process-send-string (websocket-conn websocket)
+                       (concat (unibyte-string ?\0) text
+                               (unibyte-string ?\377))))
+
+(defun websocket-openp (websocket)
+  "Returns true if the websocket exists and is open."
+  (and websocket (eq 'open (process-status (websocket-conn websocket)))))
+
+(defun websocket-close (websocket)
+  "Close the websocket and erase all the old websocket data."
+  (websocket-debug websocket "Closing websocket")
+  (when (websocket-openp websocket)
+    (process-send-string (websocket-conn websocket) (unibyte-string ?\377?\0)))
+  (kill-buffer (process-buffer (websocket-conn websocket))))
+
+(defun websocket-ensure-connected (websocket)
+  "If the websocket connection is closed, open it."
+  (unless (and (websocket-conn websocket)
+               (ecase (process-status (websocket-conn websocket))
+                 ((run open listen) t)
+                 ((stop exit signal closed connect failed nil) nil)))
+    (websocket-close websocket)
+    (let ((websocket-use-v75 (websocket-v75 websocket)))
+      (websocket-open (websocket-url websocket)
+                      (websocket-filter websocket)
+                      (websocket-close-callback websocket)))))
+
+(provide 'websocket)
+
+;;; websocket.el ends here

commit 32a113aa8971e93a382a7dfb1b069232238c18cf
Author: Dmitry Gutov <address@hidden>
Date:   Wed May 2 03:49:10 2012 +0400

    Reduce the indentation variables count
    
    * Remove `js2-consistent-level-indent-inner-bracket-p` (assume it's always 
t).
    * Merge `js2-pretty-multiline-decl-indentation-p` and
      `js2-always-indent-assigned-expr-in-decls-p` into one as
      `js2-pretty-multiline-declarations`.
    * Make the description more clear.

diff --git a/js2-mode.el b/js2-mode.el
index 8ade40a..974bcdd 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -233,27 +233,24 @@ js2-mode also binds `js2-bounce-indent-backwards' to 
Shift-Tab."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-consistent-level-indent-inner-bracket-p t
-  "Non-nil to make indentation level inner bracket consistent,
-regardless of the beginning bracket position."
-  :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-consistent-level-indent-inner-bracket-p 'booleanp)
+(defcustom js2-pretty-multiline-declarations t
+  "Non-nil to line up multiline declarations vertically:
 
-(defcustom js2-pretty-multiline-decl-indentation-p t
-  "Non-nil to line up multiline declarations vertically. See the
-function `js2-multiline-decl-indentation' for details."
-  :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-pretty-multiline-decl-indentation-p 'booleanp)
+  var a = 10,
+      b = 20,
+      c = 30;
+
+If the value is not `all', and the first assigned value in
+declaration is a function/array/object literal spanning several
+lines, it won't be indented additionally:
 
-(defcustom js2-always-indent-assigned-expr-in-decls-p nil
-  "If both `js2-pretty-multiline-decl-indentation-p' and this are non-nil,
-always additionally indent function expression or array/object literal
-assigned in a declaration, even when only one var is declared."
+  var o = {                   var bar = 2,
+    foo: 3          vs.           o = {
+  },                                foo: 3
+      bar = 2;                    };"
   :group 'js2-mode
-  :type 'boolean)
-(js2-mark-safe-local 'js2-always-indent-assigned-expr-in-decls-p 'booleanp)
+  :type 'symbol)
+(js2-mark-safe-local 'js2-pretty-multiline-declarations 'symbolp)
 
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.
@@ -9635,21 +9632,7 @@ indented to the same column as the current line."
 
 (defun js2-multiline-decl-indentation ()
   "Returns the declaration indentation column if the current line belongs
-to a multiline declaration statement.  All declarations are lined up 
vertically:
-
-var a = 10,
-    b = 20,
-    c = 30;
-
-Note that if `js2-always-indent-assigned-expr-in-decls-p' is nil, and the first
-assigned expression is a function or array/object literal, it will be indented
-differently:
-
-var o = {                               var bar = 2,
-  foo: 3                                    o = {
-},                                            foo: 3
-    bar = 2;                                };
-"
+to a multiline declaration statement.  See 
`js2-pretty-multiline-declarations'."
   (let (forward-sexp-function ; use Lisp version
         at-opening-bracket)
     (save-excursion
@@ -9745,7 +9728,7 @@ In particular, return the buffer position of the first 
`for' kwd."
     (let ((ctrl-stmt-indent (js2-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
           (continued-expr-p (js2-continued-expression-p))
-          (declaration-indent (and js2-pretty-multiline-decl-indentation-p
+          (declaration-indent (and js2-pretty-multiline-declarations
                                    (js2-multiline-decl-indentation)))
           (bracket (nth 1 parse-status))
           beg)
@@ -9770,25 +9753,19 @@ In particular, return the buffer position of the first 
`for' kwd."
         (goto-char bracket)
         (cond
          ((looking-at "[({[][ \t]*\\(/[/*]\\|$\\)")
-          (let ((p (parse-partial-sexp (point-at-bol) (point))))
-            (when (save-excursion (skip-chars-backward " \t)")
-                                  (looking-at ")"))
-              (backward-list))
-            (if (and (nth 1 p)
-                     (not js2-consistent-level-indent-inner-bracket-p))
-                (progn (goto-char (1+ (nth 1 p)))
-                       (skip-chars-forward " \t"))
-              (back-to-indentation)
-              (when (and js2-pretty-multiline-decl-indentation-p
-                         js2-always-indent-assigned-expr-in-decls-p
-                         (looking-at js2-declaration-keyword-re))
-                (goto-char (1+ (match-end 0)))))
-            (cond (same-indent-p
-                   (current-column))
-                  (continued-expr-p
-                   (+ (current-column) (* 2 js2-basic-offset)))
-                  (t
-                   (+ (current-column) js2-basic-offset)))))
+          (when (save-excursion (skip-chars-backward " \t)")
+                                (looking-at ")"))
+            (backward-list))
+          (back-to-indentation)
+          (and (eq js2-pretty-multiline-declarations 'all)
+               (looking-at js2-declaration-keyword-re)
+               (goto-char (1+ (match-end 0))))
+          (cond (same-indent-p
+                 (current-column))
+                (continued-expr-p
+                 (+ (current-column) (* 2 js2-basic-offset)))
+                (t
+                 (+ (current-column) js2-basic-offset))))
          (t
           (unless same-indent-p
             (forward-char)

commit 3044b77c782671b6ae83d8a3cd8ef37f8b038033
Author: Steve Yegge <address@hidden>
Date:   Wed May 2 04:12:16 2012 +0400

    (js2-display-error-list): make the buffer navigable

diff --git a/js2-mode.el b/js2-mode.el
index c677307..8ade40a 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10151,22 +10151,116 @@ highlighting features of `js2-mode'."
   (js2-remove-overlays)
   (setq js2-mode-ast nil))
 
-(defun js2-display-error-list ()
+(defvar js2-source-buffer nil "Linked source buffer for diagnostics view")
+(make-variable-buffer-local 'js2-source-buffer)
+
+(defun* js2-display-error-list ()
   "Display a navigable buffer listing parse errors/warnings."
   (interactive)
-  (if (not (js2-have-errors-p))
-      (message "No errors")
-    (let ((srcbuf (current-buffer))
-          (errbuf (get-buffer-create "*js-lint*"))
-          (errs (js2-errors-and-warnings)))
-      (setq errs (sort errs (lambda (e1 e2)
-                              (funcall '< (second e1) (second e2)))))
+  (unless (js2-have-errors-p)
+    (message "No errors")
+    (return-from js2-display-error-list))
+  (labels ((annotate-list
+            (lst type)
+            "Add diagnostic TYPE and line number to errs list"
+            (mapcar (lambda (err)
+                      (append err (list type
+                                        (line-number-at-pos (nth 1 err)))))
+                    lst)))
+    (let* ((srcbuf (current-buffer))
+           (errbuf (get-buffer-create "*js-lint*"))
+           (errors (annotate-list
+                    (when js2-mode-ast (js2-ast-root-errors js2-mode-ast))
+                    'js2-error))  ; must be a valid face name
+           (warnings (annotate-list
+                      (when js2-mode-ast (js2-ast-root-warnings js2-mode-ast))
+                      'js2-warning))  ; must be a valid face name
+           (all-errs (sort (append errors warnings)
+                           (lambda (e1 e2)
+                             (funcall '< (nth 1 e1) (nth 1 e2))))))
       (with-current-buffer errbuf
         (let ((inhibit-read-only t))
           (erase-buffer)
-          (dolist (err errs)
-            (insert (format "%s\n" err)))
-          (pop-to-buffer errbuf))))))
+          (dolist (err all-errs)
+            (destructuring-bind (msg-key beg end type line) err
+              (insert-text-button
+               (format "line %d: %s" line (js2-get-msg msg-key))
+               'face type
+               'follow-link "\C-m"
+               'action 'js2-error-buffer-jump
+               'js2-msg (js2-get-msg msg-key)
+               'js2-pos beg)
+              (insert "\n"))))
+        (js2-error-buffer-mode)
+        (setq js2-source-buffer srcbuf)
+        (pop-to-buffer errbuf)
+        (goto-char (point-min))
+        (unless (eobp)
+          (js2-error-buffer-view))))))
+
+(defvar js2-error-buffer-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "n" #'js2-error-buffer-next)
+    (define-key map "p" #'js2-error-buffer-prev)
+    (define-key map (kbd "RET") #'js2-error-buffer-jump)
+    (define-key map "o" #'js2-error-buffer-view)
+    (define-key map "q" #'js2-error-buffer-quit)
+    map)
+  "Keymap used for js2 diagnostics buffers.")
+
+(defun js2-error-buffer-mode ()
+  "Major mode for js2 diagnostics buffers.
+Selecting an error will jump it to the corresponding source-buffer error.
+\\{js2-error-buffer-mode-map}"
+  (interactive)
+  (setq major-mode 'js2-error-buffer-mode
+        mode-name "JS Lint Diagnostics")
+  (use-local-map js2-error-buffer-mode-map)
+  (setq truncate-lines t)
+  (set-buffer-modified-p nil)
+  (setq buffer-read-only t)
+  (run-hooks 'js2-error-buffer-mode-hook))
+
+(defun js2-error-buffer-next ()
+  "Move to next error and view it."
+  (interactive)
+  (when (zerop (forward-line 1))
+    (js2-error-buffer-view)))
+
+(defun js2-error-buffer-prev ()
+  "Move to previous error and view it."
+  (interactive)
+  (when (zerop (forward-line -1))
+    (js2-error-buffer-view)))
+
+(defun js2-error-buffer-quit ()
+  "Kill the current buffer."
+  (interactive)
+  (kill-buffer))
+
+(defun js2-error-buffer-jump (&rest ignored)
+  "Jump cursor to current error in source buffer."
+  (interactive)
+  (when (js2-error-buffer-view)
+    (pop-to-buffer js2-source-buffer)))
+
+(defun js2-error-buffer-view ()
+  "Scroll source buffer to show error at current line."
+  (interactive)
+  (cond
+   ((not (eq major-mode 'js2-error-buffer-mode))
+    (message "Not in a js2 errors buffer"))
+   ((not (buffer-live-p js2-source-buffer))
+    (message "Source buffer has been killed"))
+   ((not (wholenump (get-text-property (point) 'js2-pos)))
+    (message "There does not seem to be an error here"))
+   (t
+    (let ((pos (get-text-property (point) 'js2-pos))
+          (msg (get-text-property (point) 'js2-msg)))
+      (save-selected-window
+        (pop-to-buffer js2-source-buffer)
+        (goto-char pos)
+        (message msg))))))
 
 ;;;###autoload
 (define-derived-mode js2-mode prog-mode "Javascript-IDE"
@@ -10988,10 +11082,12 @@ move backward across N balanced expressions."
   (or (js2-errors) (js2-warnings)))
 
 (defun js2-errors-and-warnings ()
-  "Return a copy of the concatenated errors and warnings lists."
-  (and js2-mode-ast
-       (append (js2-ast-root-errors js2-mode-ast)
-               (copy-sequence (js2-ast-root-warnings js2-mode-ast)))))
+  "Return a copy of the concatenated errors and warnings lists.
+They are appended:  first the errors, then the warnings.
+Entries are of the form (MSG BEG END)."
+  (when js2-mode-ast
+    (append (js2-ast-root-errors js2-mode-ast)
+            (copy-sequence (js2-ast-root-warnings js2-mode-ast)))))
 
 (defun js2-next-error (&optional arg reset)
   "Move to next parse error.

commit 1e9af9a3d2c5af0cd64d938cae02e77f651254df
Author: Steve Yegge <address@hidden>
Date:   Wed May 2 04:06:33 2012 +0400

    (js2-echo-error): ignore when help-echo property is not a string

diff --git a/js2-mode.el b/js2-mode.el
index 236037e..c677307 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10482,9 +10482,9 @@ This ensures that the counts and `next-error' are 
correct."
 (defun js2-echo-error (old-point new-point)
   "Called by point-motion hooks."
   (let ((msg (get-text-property new-point 'help-echo)))
-    (if (and msg (or (not (current-message))
-                     (string= (current-message) "Quit")))
-        (message msg))))
+    (when (and (stringp msg) (or (not (current-message))
+                                 (string= (current-message) "Quit")))
+      (message msg))))
 
 (defalias #'js2-echo-help #'js2-echo-error)
 

commit c4c42be1f162893932038a2b6fad56888bf255ab
Author: Steve Yegge <address@hidden>
Date:   Wed May 2 04:04:41 2012 +0400

    Add message table entry for undeclared vars

diff --git a/js2-mode.el b/js2-mode.el
index 97f80dc..236037e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1720,6 +1720,9 @@ the correct number of ARGS must be provided."
 (js2-msg "msg.assn.create.strict"
          "Assignment to undeclared variable %s")
 
+(js2-msg "msg.undeclared.variable"  ; added by js2-mode
+         "Undeclared variable or function '%s'")
+
 (js2-msg "msg.ref.undefined.prop"
          "Reference to undefined property '%s'")
 
@@ -6487,7 +6490,7 @@ it is considered declared."
                     (member name js2-default-externs)
                     (member name js2-additional-externs)
                     (js2-get-defining-scope scope name))
-          (js2-report-warning "Undeclared variable" nil pos (- end pos)))))
+          (js2-report-warning "msg.undeclared.variable" name pos (- end 
pos)))))
     (setq js2-recorded-identifiers nil)))
 
 ;;; IMenu support

commit 80a8d7476ed19e38439561f7975aa8e6e33eab91
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 30 10:32:17 2012 +0400

    Don't need to clear next-error-function in `js2-mode-exit`
    
    Major mode change kills all local variables anyway

diff --git a/js2-mode.el b/js2-mode.el
index 2b28035..97f80dc 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10253,7 +10253,6 @@ highlighting features of `js2-mode'."
     (delete-overlay js2-mode-node-overlay)
     (setq js2-mode-node-overlay nil))
   (js2-remove-overlays)
-  (setq next-error-function nil)
   (setq js2-mode-ast nil)
   (remove-hook 'change-major-mode-hook #'js2-mode-exit t)
   (remove-from-invisibility-spec '(js2-outline . t))

commit 323ab3d99f0ceaad21c5903c17dbaebc501a80b8
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 30 10:22:12 2012 +0400

    Make `js2-highlight-level` buffer-local in minor mode

diff --git a/js2-mode.el b/js2-mode.el
index 1f8634b..2b28035 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10131,8 +10131,8 @@ highlighting features of `js2-mode'."
             (* js2-idle-timer-delay
                (/ (point-max) js2-dynamic-idle-timer-adjust))))
   (setq js2-mode-buffer-dirty-p t
-        js2-mode-parsing nil
-        js2-highlight-level 0)  ; no syntax highlighting
+        js2-mode-parsing nil)
+  (set (make-local-variable 'js2-highlight-level) 0) ; no syntax highlighting
   (add-hook 'after-change-functions #'js2-minor-mode-edit nil t)
   (add-hook 'change-major-mode-hook #'js2-minor-mode-exit nil t)
   (js2-reparse))

commit 522da2cde4a89b558abe92121f75027891ce9c64
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 30 10:20:27 2012 +0400

    Set next-error-function in major mode, too

diff --git a/js2-mode.el b/js2-mode.el
index 612f447..1f8634b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10230,6 +10230,7 @@ highlighting features of `js2-mode'."
   (add-hook 'change-major-mode-hook #'js2-mode-exit nil t)
   (add-hook 'after-change-functions #'js2-mode-edit nil t)
   (setq imenu-create-index-function #'js2-mode-create-imenu-index)
+  (setq next-error-function #'js2-next-error)
   (imenu-add-to-menubar (concat "IM-" mode-name))
   (add-to-invisibility-spec '(js2-outline . t))
   (set (make-local-variable 'line-move-ignore-invisible) t)
@@ -10252,6 +10253,7 @@ highlighting features of `js2-mode'."
     (delete-overlay js2-mode-node-overlay)
     (setq js2-mode-node-overlay nil))
   (js2-remove-overlays)
+  (setq next-error-function nil)
   (setq js2-mode-ast nil)
   (remove-hook 'change-major-mode-hook #'js2-mode-exit t)
   (remove-from-invisibility-spec '(js2-outline . t))

commit e3cd80fd2bc73ba0684703a25d109c6dbf50e524
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 30 10:09:31 2012 +0400

    Warn about undeclared variables in the generic way
    
    This way they show up in the warnings list, so they can be jumped between 
with
    `next-error', and are visible in `js2-minor-mode'.
    
    Highlighting and underline together look gaudy. Do something more complex?

diff --git a/js2-mode.el b/js2-mode.el
index b9a1419..612f447 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1116,17 +1116,12 @@ declarations to `js2-recorded-identifiers', which see."
   :type 'list
   :group 'js2-mode)
 
-(defface js2-external-variable
-  '((t :foreground "orange"))
-  "Face used to highlight undeclared variable identifiers.
+(defcustom js2-highlight-external-variables t
+  "Non-nil to highlight undeclared variable identifiers.
 An undeclared variable is any variable not declared with var or let
 in the current scope or any lexically enclosing scope.  If you use
 such a variable, then you are either expecting it to originate from
 another file, or you've got a potential bug."
-  :group 'js2-mode)
-
-(defcustom js2-highlight-external-variables t
-  "Non-nil to highlight undeclared variable identifiers."
   :type 'boolean
   :group 'js2-mode)
 
@@ -6492,9 +6487,7 @@ it is considered declared."
                     (member name js2-default-externs)
                     (member name js2-additional-externs)
                     (js2-get-defining-scope scope name))
-          (js2-set-face pos end 'js2-external-variable 'record)
-          (js2-record-text-property pos end 'help-echo "Undeclared variable")
-          (js2-record-text-property pos end 'point-entered #'js2-echo-help))))
+          (js2-report-warning "Undeclared variable" nil pos (- end pos)))))
     (setq js2-recorded-identifiers nil)))
 
 ;;; IMenu support

commit 1a6a981dc70cc45635e7c6c7a9df0dc916c533d7
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 30 07:41:32 2012 +0400

    Add autoload cookie for js2-minor-mode

diff --git a/js2-mode.el b/js2-mode.el
index 5d9354d..b9a1419 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10110,6 +10110,7 @@ If so, we don't ever want to use bounce-indent."
     map)
   "Keymap used when `js2-minor-mode' is active.")
 
+;;;###autoload
 (define-minor-mode js2-minor-mode
   "Minor mode for running js2 as a background linter.
 This allows you to use a different major mode for JavaScript editing,

commit e779315ccdfadb24f7749c51a530dd178998a3b1
Author: Leo Liu <address@hidden>
Date:   Sun Apr 29 17:36:11 2012 +0800

    Fix column counting by defining ack-first-column
    
    Note: ack counts column from 0.

diff --git a/ack.el b/ack.el
index 61ce7a0..a9eb7ef 100644
--- a/ack.el
+++ b/ack.el
@@ -55,6 +55,10 @@ environment variable and ~/.ackrc, which you can disable by 
the
 (defvar ack-history nil "History list for ack.")
 
 ;; Used implicitly by `define-compilation-mode'
+(defvar ack-first-column 0
+  "Value to use for `compilation-first-column' in ack buffers.")
+
+;; Used implicitly by `define-compilation-mode'
 (defvar ack-error "ack match"
   "Stem of message to print when no matches are found.")
 

commit 2fde2efff5dfd2d52b76dede7e73c3ecf9286c13
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 20 08:51:49 2012 +0400

    js2-print-array-comp-node: plus 'each', minus extra closing paren

diff --git a/js2-mode.el b/js2-mode.el
index cd46078..5d9354d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3648,8 +3648,9 @@ as opposed to required parens such as those enclosing an 
if-conditional."
       (js2-print-ast l 0))
     (when filter
       (insert " if (")
-      (js2-print-ast filter 0))
-    (insert ")]")))
+      (js2-print-ast filter 0)
+      (insert ")"))
+    (insert "]")))
 
 (defstruct (js2-array-comp-loop-node
             (:include js2-for-in-node)
@@ -3671,7 +3672,9 @@ as opposed to required parens such as those enclosing an 
if-conditional."
   (js2-visit-ast (js2-array-comp-loop-node-object n) v))
 
 (defun js2-print-array-comp-loop (n i)
-  (insert "for (")
+  (insert "for ")
+  (when (js2-array-comp-loop-node-foreach-p n) (insert "each "))
+  (insert "(")
   (js2-print-ast (js2-array-comp-loop-node-iterator n) 0)
   (insert " in ")
   (js2-print-ast (js2-array-comp-loop-node-object n) 0)

commit 8a624fa926658e86d6b8bc8e10b8abc18b387923
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 20 08:44:11 2012 +0400

    js2-print-var-decl: handle the 'let' case the same as others

diff --git a/js2-mode.el b/js2-mode.el
index bb9710c..cd46078 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3015,7 +3015,7 @@ declarations, the node begins at the position of the 
first child."
     (insert pad)
     (insert (cond
              ((= tt js2-VAR) "var ")
-             ((= tt js2-LET) "")  ; handled by parent let-{expr/stmt}
+             ((= tt js2-LET) "let ")
              ((= tt js2-CONST) "const ")
              (t
               (error "malformed var-decl node"))))

commit 2555c962ccdca0341600013a97de1aa25d6ea390
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 20 08:41:22 2012 +0400

    js2-print-list: accept that some elements may be nil
    
    let [a,,c] = [1, 2, 3];

diff --git a/js2-mode.el b/js2-mode.el
index 6f5c293..bb9710c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4549,7 +4549,7 @@ If NODE is the ast-root, returns nil."
         for arg in args
         for count from 1
         do
-        (js2-print-ast arg 0)
+        (when arg (js2-print-ast arg 0))
         (if (< count len)
             (insert (or delimiter ", ")))))
 

commit d8af108f5766b778f024702af01dfc30f3453080
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 20 06:47:53 2012 +0400

    Apply sensible changes from GNU ELPA repository
    
    * Remove `js2-function-param-node-p', it was unused.
    * Change mode title in the header.
    * Remove '-face' suffix from faces, the manual says that's redundant.

diff --git a/js2-mode.el b/js2-mode.el
index 2f30283..6f5c293 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1,4 +1,4 @@
-;;; js2-mode.el --- an improved JavaScript editing mode
+;;; js2-mode.el --- Improved JavaScript editing mode
 
 ;; Copyright (C) 2009, 2012  Free Software Foundation, Inc.
 
@@ -193,7 +193,7 @@ variable with predicate PRED."
 
 (defcustom js2-highlight-level 2
   "Amount of syntax highlighting to perform.
-0 or a negative value means do no highlighting.
+0 or a negative value means none.
 1 adds basic syntax highlighting.
 2 adds highlighting of some Ecma built-in properties.
 3 adds highlighting of many Ecma built-in functions."
@@ -1032,7 +1032,7 @@ callback to `js2-mode-wait-for-parse', and your callback 
will be
 called after the new parse tree is built.  This can take some time
 in large files.")
 
-(defface js2-warning-face
+(defface js2-warning
   `((((class color) (background light))
      (:underline  "orange"))
     (((class color) (background dark))
@@ -1041,7 +1041,7 @@ in large files.")
   "Face for JavaScript warnings."
   :group 'js2-mode)
 
-(defface js2-error-face
+(defface js2-error
   `((((class color) (background light))
      (:foreground "red"))
     (((class color) (background dark))
@@ -1050,45 +1050,45 @@ in large files.")
   "Face for JavaScript errors."
   :group 'js2-mode)
 
-(defface js2-jsdoc-tag-face
+(defface js2-jsdoc-tag
   '((t :foreground "SlateGray"))
   "Face used to highlight @whatever tags in jsdoc comments."
   :group 'js2-mode)
 
-(defface js2-jsdoc-type-face
+(defface js2-jsdoc-type
   '((t :foreground "SteelBlue"))
   "Face used to highlight {FooBar} types in jsdoc comments."
   :group 'js2-mode)
 
-(defface js2-jsdoc-value-face
+(defface js2-jsdoc-value
   '((t :foreground "PeachPuff3"))
   "Face used to highlight tag values in jsdoc comments."
   :group 'js2-mode)
 
-(defface js2-function-param-face
+(defface js2-function-param
   '((t :foreground "SeaGreen"))
   "Face used to highlight function parameters in javascript."
   :group 'js2-mode)
 
-(defface js2-instance-member-face
+(defface js2-instance-member
   '((t :foreground "DarkOrchid"))
   "Face used to highlight instance variables in javascript.
 Not currently used."
   :group 'js2-mode)
 
-(defface js2-private-member-face
+(defface js2-private-member
   '((t :foreground "PeachPuff3"))
   "Face used to highlight calls to private methods in javascript.
 Not currently used."
   :group 'js2-mode)
 
-(defface js2-private-function-call-face
+(defface js2-private-function-call
   '((t :foreground "goldenrod"))
   "Face used to highlight calls to private functions in javascript.
 Not currently used."
   :group 'js2-mode)
 
-(defface js2-jsdoc-html-tag-name-face
+(defface js2-jsdoc-html-tag-name
   '((((class color) (min-colors 88) (background light))
      (:foreground "rosybrown"))
     (((class color) (min-colors 8) (background dark))
@@ -1098,7 +1098,7 @@ Not currently used."
     "Face used to highlight jsdoc html tag names"
   :group 'js2-mode)
 
-(defface js2-jsdoc-html-tag-delimiter-face
+(defface js2-jsdoc-html-tag-delimiter
   '((((class color) (min-colors 88) (background light))
      (:foreground "dark khaki"))
     (((class color) (min-colors 8) (background dark))
@@ -1116,7 +1116,7 @@ declarations to `js2-recorded-identifiers', which see."
   :type 'list
   :group 'js2-mode)
 
-(defface js2-external-variable-face
+(defface js2-external-variable
   '((t :foreground "orange"))
   "Face used to highlight undeclared variable identifiers.
 An undeclared variable is any variable not declared with var or let
@@ -4510,13 +4510,6 @@ If NODE is the ast-root, returns nil."
                            (js2-node-parent-script-or-fn
                             (js2-node-parent-script-or-fn node))))))
 
-(defun js2-function-param-node-p (node)
-  "Return non-nil if NODE is a param node of a `js2-function-node'."
-  (let ((parent (js2-node-parent node)))
-    (and parent
-         (js2-function-node-p parent)
-         (memq node (js2-function-node-params parent)))))
-
 (defun js2-mode-shift-kids (kids start offset)
   (dolist (kid kids)
     (if (> (js2-node-pos kid) start)
@@ -6404,21 +6397,21 @@ of a simple name.  Called before EXPR has a parent 
node."
 (defun js2-jsdoc-highlight-helper ()
   (js2-set-face (match-beginning 1)
                 (match-end 1)
-                'js2-jsdoc-tag-face)
+                'js2-jsdoc-tag)
   (if (match-beginning 2)
       (if (save-excursion
             (goto-char (match-beginning 2))
             (= (char-after) ?{))
           (js2-set-face (1+ (match-beginning 2))
                         (1- (match-end 2))
-                        'js2-jsdoc-type-face)
+                        'js2-jsdoc-type)
         (js2-set-face (match-beginning 2)
                       (match-end 2)
-                      'js2-jsdoc-value-face)))
+                      'js2-jsdoc-value)))
   (if (match-beginning 3)
       (js2-set-face (match-beginning 3)
                     (match-end 3)
-                    'js2-jsdoc-value-face)))
+                    'js2-jsdoc-value)))
 
 (defun js2-highlight-jsdoc (ast)
   "Highlight doc comment tags."
@@ -6445,13 +6438,13 @@ of a simple name.  Called before EXPR has a parent 
node."
             (while (re-search-forward js2-jsdoc-html-tag-regexp nil t)
               (js2-set-face (match-beginning 1)
                             (match-end 1)
-                            'js2-jsdoc-html-tag-delimiter-face)
+                            'js2-jsdoc-html-tag-delimiter)
               (js2-set-face (match-beginning 2)
                             (match-end 2)
-                            'js2-jsdoc-html-tag-name-face)
+                            'js2-jsdoc-html-tag-name)
               (js2-set-face (match-beginning 3)
                             (match-end 3)
-                            'js2-jsdoc-html-tag-delimiter-face))))))))
+                            'js2-jsdoc-html-tag-delimiter))))))))
 
 (defun js2-highlight-assign-targets (node left right)
   "Highlight function properties and external variables."
@@ -6496,7 +6489,7 @@ it is considered declared."
                     (member name js2-default-externs)
                     (member name js2-additional-externs)
                     (js2-get-defining-scope scope name))
-          (js2-set-face pos end 'js2-external-variable-face 'record)
+          (js2-set-face pos end 'js2-external-variable 'record)
           (js2-record-text-property pos end 'help-echo "Undeclared variable")
           (js2-record-text-property pos end 'point-entered #'js2-echo-help))))
     (setq js2-recorded-identifiers nil)))
@@ -6959,7 +6952,7 @@ The flags, if any, are saved in 
`js2-current-flagged-token'."
       (when js2-parse-ide-mode
         (cond
          ((minusp tt)
-          (js2-record-face 'js2-error-face))
+          (js2-record-face 'js2-error))
          ((setq face (aref js2-kwd-tokens tt))
           (js2-record-face face))
          ((and (= tt js2-NAME)
@@ -7279,12 +7272,12 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
               (setq param (js2-parse-primary-expr-lhs))
               (js2-define-destruct-symbols param
                                            js2-LP
-                                           'js2-function-param-face)
+                                           'js2-function-param)
               (push param params))
              ;; simple name
              (t
               (js2-must-match js2-NAME "msg.no.parm")
-              (js2-record-face 'js2-function-param-face)
+              (js2-record-face 'js2-function-param)
               (setq param (js2-create-name-node))
               (js2-define-symbol js2-LP js2-ts-string param)
               (push param params)))
@@ -10449,7 +10442,7 @@ Defaults to point."
   "Highlight syntax errors."
   (when js2-mode-show-parse-errors
     (dolist (e (js2-ast-root-errors js2-mode-ast))
-      (js2-mode-show-warn-or-err e 'js2-error-face))))
+      (js2-mode-show-warn-or-err e 'js2-error))))
 
 (defun js2-mode-remove-suppressed-warnings ()
   "Take suppressed warnings out of the AST warnings list.
@@ -10483,7 +10476,7 @@ This ensures that the counts and `next-error' are 
correct."
   "Highlight strict-mode warnings."
   (when js2-mode-show-strict-warnings
     (dolist (e (js2-ast-root-warnings js2-mode-ast))
-      (js2-mode-show-warn-or-err e 'js2-warning-face))))
+      (js2-mode-show-warn-or-err e 'js2-warning))))
 
 (defun js2-echo-error (old-point new-point)
   "Called by point-motion hooks."

commit 8806e482a3fd1762000e9702e00ce9f3f70767d0
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 20 05:54:44 2012 +0400

    Reapply the fix from 83ba85

diff --git a/js2-mode.el b/js2-mode.el
index 8846332..2f30283 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9610,12 +9610,13 @@ and comments have been removed."
   (save-excursion
     (back-to-indentation)
     (or (js2-looking-at-operator-p)
-        (when (js2-re-search-backward "\n" nil t)  ;; comment
+        (when (js2-re-search-backward "\n" nil t)  ;; skip comments
           (skip-chars-backward " \t")
-          (backward-char)
-          (when (js2-looking-at-operator-p)
+          (unless (bolp) ;; previous line is empty
             (backward-char)
-            (not (looking-at "\\*\\|++\\|--\\|/[/*]")))))))
+            (when (js2-looking-at-operator-p)
+              (backward-char)
+              (not (looking-at "\\*\\|++\\|--\\|/[/*]"))))))))
 
 (defun js2-end-of-do-while-loop-p ()
   "Return non-nil if word after point is `while' of a do-while

commit 1ddd03c29b469ae525c7783168c082099684f2a3
Author: Steve Yegge <address@hidden>
Date:   Fri Apr 20 05:28:36 2012 +0400

    Make the mode a better Emacs citizen
    
    New features:
    * Introduce `js2-minor-mode', to run parser with another major mode active.
    * Add `js2-display-error-list'.
    
    Breaking changes:
    * Emacs 24 only.
    * Don't set up mode association automatically for *.js files.
    * Get rid of the mirror-mode (use electric-pair-mode).
    * Get rid of the auto-indent code (use electric-indent-mode).
    * Get rid of the js2-rebind-eol-bol-keys.
    * Don't rebind RET. Use M-j to extend comments.
    * Don't bind `js2-mark-defun' and `js2-narrow-to-defun'.
    
    Other changes:
    * Derive from `prog-mode'.
    * Improve documentation style.
    * Consistently use 'js2-' prefix.
    * Replace `defsubst' with `defun' is many cases.
    * Don't use `save-match-data' unless required (which is currently never).
    
    Incorporates a patch by Stefan Monnier.

diff --git a/js2-mode.el b/js2-mode.el
index 73c9608..8846332 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1,6 +1,6 @@
 ;;; js2-mode.el --- an improved JavaScript editing mode
 
-;; Copyright (C) 2009  Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2012  Free Software Foundation, Inc.
 
 ;; Author:  Steve Yegge <address@hidden>
 ;; Contributors:  mooz <address@hidden>
@@ -43,6 +43,17 @@
 ;;  - typing helpers such as automatic insertion of matching braces/parens
 ;;  - many customization options
 
+;; Installation:
+;;
+;; To install it as your major mode for JavaScript editing:
+
+;;   (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+
+;; Alternately, to install it as a minor mode just for JavaScript linting,
+;; you must add it to the appropriate major-mode hook.  Normally this would be:
+
+;;   (add-hook 'js-mode-hook 'js2-minor-mode)
+
 ;; To customize how it works:
 ;;   M-x customize-group RET js2-mode RET
 
@@ -75,6 +86,8 @@
   (require 'cc-langs)    ; it's here in Emacs 21...
   (require 'cc-engine))  ; for `c-paragraph-start' et. al.
 
+(defvar electric-layout-rules)
+
 ;;; Externs (variables presumed to be defined by the host system)
 
 (defvar js2-ecma-262-externs
@@ -155,7 +168,7 @@ variable `js2-include-browser-externs'.")
 (defvar js2-rhino-externs
   (mapcar 'symbol-name
           '(Packages importClass importPackage com org java
-            ;; Global object (shell) externs
+            ;; Global object (shell) externs.
             defineClass deserialize doctest gc help load
             loadClass print quit readFile readUrl runCommand seal
             serialize spawn sync toint32 version))
@@ -178,8 +191,6 @@ variable with predicate PRED."
   (make-variable-buffer-local name)
   (put name 'safe-local-variable pred))
 
-(defvar js2-emacs22 (>= emacs-major-version 22))
-
 (defcustom js2-highlight-level 2
   "Amount of syntax highlighting to perform.
 0 or a negative value means do no highlighting.
@@ -209,18 +220,6 @@ Similar to `c-basic-offset'."
   :type 'integer)
 (js2-mark-safe-local 'js2-basic-offset 'integerp)
 
-;; TODO(stevey):  move this code into a separate minor mode.
-(defcustom js2-mirror-mode nil
-  "Non-nil to insert closing brackets, parens, etc. automatically."
-  :group 'js2-mode
-  :type 'boolean)
-
-(defcustom js2-auto-indent-p nil
-  "Automatic indentation with punctuation characters.
-If non-nil, the current line is indented when certain punctuations
-are inserted."
-  :group 'js2-mode
-  :type 'boolean)
 
 (defcustom js2-bounce-indent-p nil
   "Non-nil to have indent-line function choose among alternatives.
@@ -243,7 +242,7 @@ regardless of the beginning bracket position."
 
 (defcustom js2-pretty-multiline-decl-indentation-p t
   "Non-nil to line up multiline declarations vertically. See the
-function `js-multiline-decl-indentation' for details."
+function `js2-multiline-decl-indentation' for details."
   :group 'js2-mode
   :type 'boolean)
 (js2-mark-safe-local 'js2-pretty-multiline-decl-indentation-p 'booleanp)
@@ -268,18 +267,6 @@ This is unusual for Emacs modes but common in IDEs like 
Eclipse."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-rebind-eol-bol-keys t
-  "Non-nil to rebind `beginning-of-line' and `end-of-line' keys.
-If non-nil, bounce between bol/eol and first/last non-whitespace char."
-  :group 'js2-mode
-  :type 'boolean)
-
-(defcustom js2-electric-keys '("{" "}" "(" ")" "[" "]" ":" ";" "," "*")
-  "Keys that auto-indent when `js2-auto-indent-p' is non-nil.
-Each value in the list is passed to `define-key'."
-  :type 'list
-  :group 'js2-mode)
-
 (defcustom js2-idle-timer-delay 0.2
   "Delay in secs before re-parsing after user makes changes.
 Multiplied by `js2-dynamic-idle-timer-adjust', which see."
@@ -412,17 +399,12 @@ This is useful for xulrunner apps."
   :type 'boolean
   :group 'js2-mode)
 
-(defcustom js2-cleanup-whitespace nil
-  "Non-nil to invoke `delete-trailing-whitespace' before saves."
-  :type 'boolean
-  :group 'js2-mode)
-
 (defcustom js2-move-point-on-right-click t
   "Non-nil to move insertion point when you right-click.
 This makes right-click context menu behavior a bit more intuitive,
 since menu operations generally apply to the point.  The exception
 is if there is a region selection, in which case the point does -not-
-move, so cut/copy/paste etc. can work properly.
+move, so cut/copy/paste can work properly.
 
 Note that IntelliJ moves the point, and Eclipse leaves it alone,
 so this behavior is customizable."
@@ -474,7 +456,7 @@ which doesn't seem particularly useful, but Rhino permits 
it."
   :type 'boolean
   :group 'js2-mode)
 
-(defvar js2-mode-version 20101228
+(defvar js2-mode-version 20120416
   "Release number for `js2-mode'.")
 
 ;; scanner variables
@@ -834,7 +816,7 @@ Will only be used when we finish implementing the 
interpreter.")
 
 (defcustom js2-global-externs nil
   "A list of any extern names you'd like to consider always declared.
-This list is global and is used by all js2-mode files.
+This list is global and is used by all `js2-mode' files.
 You can create buffer-local externs list using `js2-additional-externs'.
 
 There is also a buffer-local variable `js2-default-externs',
@@ -885,7 +867,7 @@ See `js2-additional-externs' for more information about 
externs."
 It is used to decide whether variables are considered undeclared
 for purposes of highlighting.
 
-Each entry is a lisp string.  The string should be the fully qualified
+Each entry is a Lisp string.  The string should be the fully qualified
 name of an external entity.  All externs should be added to this list,
 so that as js2-mode's processing improves it can take advantage of them.
 
@@ -1107,41 +1089,25 @@ Not currently used."
   :group 'js2-mode)
 
 (defface js2-jsdoc-html-tag-name-face
-  (if js2-emacs22
-      '((((class color) (min-colors 88) (background light))
-         (:foreground "rosybrown"))
-        (((class color) (min-colors 8) (background dark))
-         (:foreground "yellow"))
-        (((class color) (min-colors 8) (background light))
-         (:foreground "magenta")))
-    '((((type tty pc) (class color) (background light))
-       (:foreground "magenta"))
-      (((type tty pc) (class color) (background dark))
-       (:foreground "yellow"))
-      (t (:foreground "RosyBrown"))))
+  '((((class color) (min-colors 88) (background light))
+     (:foreground "rosybrown"))
+    (((class color) (min-colors 8) (background dark))
+     (:foreground "yellow"))
+    (((class color) (min-colors 8) (background light))
+     (:foreground "magenta")))
     "Face used to highlight jsdoc html tag names"
   :group 'js2-mode)
 
 (defface js2-jsdoc-html-tag-delimiter-face
-  (if js2-emacs22
-      '((((class color) (min-colors 88) (background light))
-         (:foreground "dark khaki"))
-        (((class color) (min-colors 8) (background dark))
-         (:foreground "green"))
-        (((class color) (min-colors 8) (background light))
-         (:foreground "green")))
-    '((((type tty pc) (class color) (background light))
-       (:foreground "green"))
-      (((type tty pc) (class color) (background dark))
-       (:foreground "green"))
-      (t (:foreground "dark khaki"))))
+  '((((class color) (min-colors 88) (background light))
+     (:foreground "dark khaki"))
+    (((class color) (min-colors 8) (background dark))
+     (:foreground "green"))
+    (((class color) (min-colors 8) (background light))
+     (:foreground "green")))
   "Face used to highlight brackets in jsdoc html tags."
   :group 'js2-mode)
 
-(defface js2-magic-paren-face
-  '((t :underline t))
-  "Face used to color parens that will be auto-overwritten."
-  :group 'js2-mode)
 
 (defcustom js2-post-parse-callbacks nil
   "A list of callback functions invoked after parsing finishes.
@@ -1173,10 +1139,6 @@ another file, or you've got a potential bug."
   (let ((map (make-sparse-keymap))
         keys)
     (define-key map [mouse-1] #'js2-mode-show-node)
-    (define-key map (kbd "C-m") #'js2-enter-key)
-    (when js2-rebind-eol-bol-keys
-      (define-key map (kbd "C-a") #'js2-beginning-of-line)
-      (define-key map (kbd "C-e") #'js2-end-of-line))
     (define-key map (kbd "C-c C-e") #'js2-mode-hide-element)
     (define-key map (kbd "C-c C-s") #'js2-mode-show-element)
     (define-key map (kbd "C-c C-a") #'js2-mode-show-all)
@@ -1184,21 +1146,7 @@ another file, or you've got a potential bug."
     (define-key map (kbd "C-c C-t") #'js2-mode-toggle-hide-comments)
     (define-key map (kbd "C-c C-o") #'js2-mode-toggle-element)
     (define-key map (kbd "C-c C-w") #'js2-mode-toggle-warnings-and-errors)
-    (define-key map (kbd "C-c C-`") #'js2-next-error)
-    ;; also define user's preference for next-error, if available
-    (if (setq keys (where-is-internal #'next-error))
-        (define-key map (car keys) #'js2-next-error))
-    (define-key map (or (car (where-is-internal #'mark-defun))
-                        (kbd "M-C-h"))
-      #'js2-mark-defun)
-    (define-key map (or (car (where-is-internal #'narrow-to-defun))
-                        (kbd "C-x nd"))
-      #'js2-narrow-to-defun)
     (define-key map [down-mouse-3] #'js2-down-mouse-3)
-    (when js2-auto-indent-p
-      (mapc (lambda (key)
-              (define-key map key #'js2-insert-and-indent))
-            js2-electric-keys))
     (when js2-bounce-indent-p
       (define-key map (kbd "<backtab>") #'js2-indent-bounce-backwards))
 
@@ -1217,7 +1165,7 @@ another file, or you've got a potential bug."
       '("--"))
 
     (define-key map [menu-bar javascript next-error]
-      '(menu-item "Next warning or error" js2-next-error
+      '(menu-item "Next warning or error" next-error
                   :enabled (and js2-mode-ast
                                 (or (js2-ast-root-errors js2-mode-ast)
                                     (js2-ast-root-warnings js2-mode-ast)))
@@ -1314,14 +1262,14 @@ First match-group is the leading whitespace.")
 (defvar js2-mode-verbose-parse-p js2-mode-dev-mode-p
   "Non-nil to emit status messages during parsing.")
 
-(defvar js2-mode-functions-hidden nil "private variable")
-(defvar js2-mode-comments-hidden nil "private variable")
+(defvar js2-mode-functions-hidden nil "Private variable.")
+(defvar js2-mode-comments-hidden nil "Private variable.")
 
 (defvar js2-mode-syntax-table
   (let ((table (make-syntax-table)))
     (c-populate-syntax-table table)
     table)
-  "Syntax table used in js2-mode buffers.")
+  "Syntax table used in `js2-mode' buffers.")
 
 (defvar js2-mode-abbrev-table nil
   "Abbrev table in use in `js2-mode' buffers.")
@@ -1341,7 +1289,7 @@ First match-group is the leading whitespace.")
 
 (defvar js2-message-table
   (make-hash-table :test 'equal :size 250)
-  "Contains localized messages for js2-mode.")
+  "Contains localized messages for `js2-mode'.")
 
 ;; TODO(stevey):  construct this table at compile-time.
 (defmacro js2-msg (key &rest strings)
@@ -2017,7 +1965,7 @@ Returns nil if element is not found in the list."
     result))
 
 (defmacro js2-time (form)
-  "Evaluate FORM, discard result, and return elapsed time in sec"
+  "Evaluate FORM, discard result, and return elapsed time in sec."
   (declare (debug t))
   (let ((beg (make-symbol "--js2-time-beg--"))
         (delta (make-symbol "--js2-time-end--")))
@@ -2034,8 +1982,8 @@ Returns nil if element is not found in the list."
   (and (>= pos (point-at-bol))
        (<= pos (point-at-eol))))
 
-(defsubst js2-same-line-2 (p1 p2)
-  "Return t if p1 is on the same line as p2."
+(defun js2-same-line-2 (p1 p2)
+  "Return t if P1 is on the same line as P2."
   (save-excursion
     (goto-char p1)
     (js2-same-line p2)))
@@ -2050,13 +1998,13 @@ Returns nil if element is not found in the list."
 
 ;; I'd like to associate errors with nodes, but for now the
 ;; easiest thing to do is get the context info from the last token.
-(defsubst js2-record-parse-error (msg &optional arg pos len)
+(defun js2-record-parse-error (msg &optional arg pos len)
   (push (list (list msg arg)
               (or pos js2-token-beg)
               (or len (- js2-token-end js2-token-beg)))
         js2-parsed-errors))
 
-(defsubst js2-report-error (msg &optional msg-arg pos len)
+(defun js2-report-error (msg &optional msg-arg pos len)
   "Signal a syntax error or record a parse error."
   (if js2-recover-from-parse-errors
       (js2-record-parse-error msg msg-arg pos len)
@@ -2068,7 +2016,7 @@ Returns nil if element is not found in the list."
                   (current-column))
                 js2-ts-hit-eof))))
 
-(defsubst js2-report-warning (msg &optional msg-arg pos len)
+(defun js2-report-warning (msg &optional msg-arg pos len)
   (if js2-compiler-report-warning-as-error
       (js2-report-error msg msg-arg pos len)
     (push (list (list msg msg-arg)
@@ -2076,7 +2024,7 @@ Returns nil if element is not found in the list."
                 (or len (- js2-token-end js2-token-beg)))
           js2-parsed-warnings)))
 
-(defsubst js2-add-strict-warning (msg-id &optional msg-arg beg end)
+(defun js2-add-strict-warning (msg-id &optional msg-arg beg end)
   (if js2-compiler-strict-mode
       (js2-report-warning msg-id msg-arg beg
                           (and beg end (- end beg)))))
@@ -2102,26 +2050,6 @@ Returns nil if element is not found in the list."
 (defsubst js2-flag-not-set-p (flags flag)
   (zerop (logand flags flag)))
 
-;; Stolen shamelessly from James Clark's nxml-mode.
-(defmacro js2-with-unmodifying-text-property-changes (&rest body)
-  "Evaluate BODY without any text property changes modifying the buffer.
-Any text properties changes happen as usual but the changes are not treated as
-modifications to the buffer."
-  (declare (indent 0) (debug t))
-  (let ((modified (make-symbol "modified")))
-    `(let ((,modified (buffer-modified-p))
-          (inhibit-read-only t)
-          (inhibit-modification-hooks t)
-          (buffer-undo-list t)
-          (deactivate-mark nil)
-          ;; Apparently these avoid file locking problems.
-          (buffer-file-name nil)
-          (buffer-file-truename nil))
-       (unwind-protect
-          (progn ,@body)
-        (unless ,modified
-          (restore-buffer-modified-p nil))))))
-
 (defmacro js2-with-underscore-as-word-syntax (&rest body)
   "Evaluate BODY with the _ character set to be word-syntax."
   (declare (indent 0) (debug t))
@@ -2146,21 +2074,21 @@ Handles unicode and latin chars properly."
 ;;; AST struct and function definitions
 
 ;; flags for ast node property 'member-type (used for e4x operators)
-(defvar js2-property-flag    #x1 "property access: element is valid name")
-(defvar js2-attribute-flag   #x2 "address@hidden or address@hidden")
-(defvar js2-descendants-flag #x4 "x..y or address@hidden")
+(defvar js2-property-flag    #x1 "Property access: element is valid name.")
+(defvar js2-attribute-flag   #x2 "address@hidden or address@hidden")
+(defvar js2-descendants-flag #x4 "x..y or address@hidden")
 
 (defsubst js2-relpos (pos anchor)
   "Convert POS to be relative to ANCHOR.
 If POS is nil, returns nil."
   (and pos (- pos anchor)))
 
-(defsubst js2-make-pad (indent)
+(defun js2-make-pad (indent)
   (if (zerop indent)
       ""
     (make-string (* indent js2-basic-offset) ? )))
 
-(defsubst js2-visit-ast (node callback)
+(defun js2-visit-ast (node callback)
   "Visit every node in ast NODE with visitor CALLBACK.
 
 CALLBACK is a function that takes two arguments:  (NODE END-P).  It is
@@ -2173,7 +2101,7 @@ callback is called immediately with a non-nil END-P 
argument.
 
 The node traversal is approximately lexical-order, although there
 are currently no guarantees around this."
-  (if node
+  (when node
     (let ((vfunc (get (aref node 0) 'js2-visitor)))
       ;; visit the node
       (when  (funcall callback node nil)
@@ -2208,7 +2136,7 @@ are currently no guarantees around this."
   (setf (js2-node-props node)
         (cons (list prop value) (js2-node-props node))))
 
-(defsubst js2-fixup-starts (n nodes)
+(defun js2-fixup-starts (n nodes)
   "Adjust the start positions of NODES to be relative to N.
 Any node in the list may be nil, for convenience."
   (dolist (node nodes)
@@ -2216,7 +2144,7 @@ Any node in the list may be nil, for convenience."
       (setf (js2-node-pos node) (- (js2-node-pos node)
                                    (js2-node-pos n))))))
 
-(defsubst js2-node-add-children (parent &rest nodes)
+(defun js2-node-add-children (parent &rest nodes)
   "Set parent node of NODES to PARENT, and return PARENT.
 Does nothing if we're not recording parent links.
 If any given node in NODES is nil, doesn't record that link."
@@ -2226,7 +2154,7 @@ If any given node in NODES is nil, doesn't record that 
link."
          (setf (js2-node-parent node) parent))))
 
 ;; Non-recursive since it's called a frightening number of times.
-(defsubst js2-node-abs-pos (n)
+(defun js2-node-abs-pos (n)
   (let ((pos (js2-node-pos n)))
     (while (setq n (js2-node-parent n))
       (setq pos (+ pos (js2-node-pos n))))
@@ -2236,7 +2164,7 @@ If any given node in NODES is nil, doesn't record that 
link."
   "Return absolute buffer position of end of N."
   (+ (js2-node-abs-pos n) (js2-node-len n)))
 
-;; It's important to make sure block nodes have a lisp list for the
+;; It's important to make sure block nodes have a Lisp list for the
 ;; child nodes, to limit printing recursion depth in an AST that
 ;; otherwise consists of defstruct vectors.  Emacs will crash printing
 ;; a sufficiently large vector tree.
@@ -2250,12 +2178,12 @@ If any given node in NODES is nil, doesn't record that 
link."
                                                     props
                                                     kids)))
   "A block of statements."
-  kids)  ; a lisp list of the child statement nodes
+  kids)  ; a Lisp list of the child statement nodes
 
 (put 'cl-struct-js2-block-node 'js2-visitor 'js2-visit-block)
 (put 'cl-struct-js2-block-node 'js2-printer 'js2-print-block)
 
-(defsubst js2-visit-block (ast callback)
+(defun js2-visit-block (ast callback)
   "Visit the `js2-block-node' children of AST."
   (dolist (kid (js2-block-node-kids ast))
     (js2-visit-ast kid callback)))
@@ -2318,7 +2246,7 @@ Returns `js2-scope' in which NAME is defined, or nil if 
not found."
         (setq scope (js2-scope-parent-scope scope))))
     result))
 
-(defsubst js2-scope-get-symbol (scope name)
+(defun js2-scope-get-symbol (scope name)
   "Return symbol table entry for NAME in SCOPE.
 NAME can be a string or symbol.   Returns a `js2-symbol' or nil if not found."
   (and (js2-scope-symbol-table scope)
@@ -2327,9 +2255,9 @@ NAME can be a string or symbol.   Returns a `js2-symbol' 
or nil if not found."
                     (intern name))
                   (js2-scope-symbol-table scope)))))
 
-(defsubst js2-scope-put-symbol (scope name symbol)
+(defun js2-scope-put-symbol (scope name symbol)
   "Enter SYMBOL into symbol-table for SCOPE under NAME.
-NAME can be a lisp symbol or string.  SYMBOL is a `js2-symbol'."
+NAME can be a Lisp symbol or string.  SYMBOL is a `js2-symbol'."
   (let* ((table (js2-scope-symbol-table scope))
          (sym (if (symbolp name) name (intern name)))
          (entry (assq sym table)))
@@ -2367,8 +2295,8 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                      len
                                                      var-decls
                                                      fun-decls)))
-  functions   ; lisp list of nested functions
-  regexps     ; lisp list of (string . flags)
+  functions   ; Lisp list of nested functions
+  regexps     ; Lisp list of (string . flags)
   symbols     ; alist (every symbol gets unique index)
   (param-count 0)
   var-names   ; vector of string names
@@ -2391,9 +2319,9 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                   buffer)))
   "The root node of a js2 AST."
   buffer         ; the source buffer from which the code was parsed
-  comments       ; a lisp list of comments, ordered by start position
-  errors         ; a lisp list of errors found during parsing
-  warnings       ; a lisp list of warnings found during parsing
+  comments       ; a Lisp list of comments, ordered by start position
+  errors         ; a Lisp list of errors found during parsing
+  warnings       ; a Lisp list of warnings found during parsing
   node-count)    ; number of nodes in the tree, including the root
 
 (put 'cl-struct-js2-ast-root 'js2-visitor 'js2-visit-ast-root)
@@ -2434,7 +2362,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
   expr)
 
 (defsubst js2-expr-stmt-node-set-has-result (node)
-  "Change the node type to `js2-EXPR_RESULT'.  Used for code generation."
+  "Change NODE type to `js2-EXPR_RESULT'.  Used for code generation."
   (setf (js2-node-type node) js2-EXPR_RESULT))
 
 (put 'cl-struct-js2-expr-stmt-node 'js2-visitor 'js2-visit-expr-stmt-node)
@@ -2491,10 +2419,8 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-while-node (&key (type js2-WHILE)
                                                     (pos js2-token-beg)
-                                                    len
-                                                    body
-                                                    condition
-                                                    lp
+                                                    len body
+                                                    condition lp
                                                     rp)))
   "AST node for while-loop."
   condition)    ; while-condition
@@ -2519,13 +2445,9 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-for-node (&key (type js2-FOR)
                                                   (pos js2-ts-cursor)
-                                                  len
-                                                  body
-                                                  init
+                                                  len body init
                                                   condition
-                                                  update
-                                                  lp
-                                                  rp)))
+                                                  update lp rp)))
   "AST node for a C-style for-loop."
   init       ; initialization expression
   condition  ; loop condition
@@ -2557,14 +2479,12 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-for-in-node (&key (type js2-FOR)
                                                      (pos js2-ts-cursor)
-                                                     len
-                                                     body
+                                                     len body
                                                      iterator
                                                      object
                                                      in-pos
                                                      each-pos
-                                                     foreach-p
-                                                     lp
+                                                     foreach-p lp
                                                      rp)))
   "AST node for a for..in loop."
   iterator  ; [var] foo in ...
@@ -2623,12 +2543,10 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-if-node (&key (type js2-IF)
                                                  (pos js2-ts-cursor)
-                                                 len
-                                                 condition
+                                                 len condition
                                                  then-part
                                                  else-pos
-                                                 else-part
-                                                 lp
+                                                 else-part lp
                                                  rp)))
   "AST node for an if-statement."
   condition   ; expression
@@ -2677,7 +2595,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                   finally-block)))
   "AST node for a try-statement."
   try-block
-  catch-clauses  ; a lisp list of `js2-catch-node'
+  catch-clauses  ; a Lisp list of `js2-catch-node'
   finally-block) ; a `js2-finally-node'
 
 (put 'cl-struct-js2-try-node 'js2-visitor 'js2-visit-try-node)
@@ -2712,8 +2630,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                     param
                                                     guard-kwd
                                                     guard-expr
-                                                    block
-                                                    lp
+                                                    block lp
                                                     rp)))
   "AST node for a catch clause."
   param       ; destructuring form or simple name node
@@ -2750,8 +2667,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-finally-node (&key (type js2-FINALLY)
                                                       (pos js2-ts-cursor)
-                                                      len
-                                                      body)))
+                                                      len body)))
   "AST node for a finally clause."
   body)  ; a `js2-node', often but not always a block node
 
@@ -2774,12 +2690,11 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
                                                      (pos js2-ts-cursor)
                                                      len
                                                      discriminant
-                                                     cases
-                                                     lp
+                                                     cases lp
                                                      rp)))
   "AST node for a switch statement."
   discriminant  ; a `js2-node' (switch expression)
-  cases  ; a lisp list of `js2-case-node'
+  cases  ; a Lisp list of `js2-case-node'
   lp     ; position of open-paren for discriminant, nil if omitted
   rp)    ; position of close-paren for discriminant, nil if omitted
 
@@ -2806,9 +2721,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-case-node (&key (type js2-CASE)
                                                    (pos js2-ts-cursor)
-                                                   len
-                                                   kids
-                                                   expr)))
+                                                   len kids expr)))
   "AST node for a case clause of a switch statement."
   expr)   ; the case expression (nil for default)
 
@@ -2836,8 +2749,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-throw-node (&key (type js2-THROW)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    expr)))
+                                                    len expr)))
   "AST node for a throw statement."
   expr)   ; the expression to throw
 
@@ -2857,11 +2769,8 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-with-node (&key (type js2-WITH)
                                                    (pos js2-ts-cursor)
-                                                   len
-                                                   object
-                                                   body
-                                                   lp
-                                                   rp)))
+                                                   len object
+                                                   body lp rp)))
   "AST node for a with-statement."
   object
   body
@@ -2888,8 +2797,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor nil)
             (:constructor make-js2-label-node (&key (type js2-LABEL)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    name)))
+                                                    len name)))
   "AST node for a statement label or case label."
   name   ; a string
   loop)  ; for validating and code-generating continue-to-label
@@ -2909,12 +2817,10 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             ;; no-side-effects warnings, hence js2-EXPR_RESULT.
             (:constructor make-js2-labeled-stmt-node (&key (type 
js2-EXPR_RESULT)
                                                            (pos js2-ts-cursor)
-                                                           len
-                                                           labels
-                                                           stmt)))
+                                                           len labels stmt)))
   "AST node for a statement with one or more labels.
 Multiple labels for a statement are collapsed into the labels field."
-  labels  ; lisp list of `js2-label-node'
+  labels  ; Lisp list of `js2-label-node'
   stmt)   ; the statement these labels are for
 
 (put 'cl-struct-js2-labeled-stmt-node 'js2-visitor 'js2-visit-labeled-stmt)
@@ -2962,6 +2868,7 @@ NODE is a `js2-labels-node'.  LABEL is an identifier."
   target) ; target js2-labels-node or loop/switch statement
 
 (defun js2-visit-jump-node (n v)
+  ;; We don't visit the target, since it's a back-link.
   (js2-visit-ast (js2-jump-node-label n) v))
 
 (defstruct (js2-break-node
@@ -2969,9 +2876,7 @@ NODE is a `js2-labels-node'.  LABEL is an identifier."
             (:constructor nil)
             (:constructor make-js2-break-node (&key (type js2-BREAK)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    label
-                                                    target)))
+                                                    len label target)))
   "AST node for a break statement.
 The label field is a `js2-name-node', possibly nil, for the named label
 if provided.  E.g. in 'break foo', it represents 'foo'.  The target field
@@ -2992,9 +2897,7 @@ is the target of the break - a label node or enclosing 
loop/switch statement.")
             (:constructor nil)
             (:constructor make-js2-continue-node (&key (type js2-CONTINUE)
                                                        (pos js2-ts-cursor)
-                                                       len
-                                                       label
-                                                       target)))
+                                                       len label target)))
   "AST node for a continue statement.
 The label field is the user-supplied enclosing label name, a `js2-name-node'.
 It is nil if continue specifies no label.  The target field is the jump target:
@@ -3019,18 +2922,16 @@ a `js2-label-node' or the innermost enclosing loop.")
                                                        (ftype 'FUNCTION)
                                                        (form 
'FUNCTION_STATEMENT)
                                                        (name "")
-                                                       params
-                                                       body
-                                                       lp
-                                                       rp)))
+                                                       params body
+                                                       lp rp)))
   "AST node for a function declaration.
-The `params' field is a lisp list of nodes.  Each node is either a simple
+The `params' field is a Lisp list of nodes.  Each node is either a simple
 `js2-name-node', or if it's a destructuring-assignment parameter, a
 `js2-array-node' or `js2-object-node'."
   ftype            ; FUNCTION, GETTER or SETTER
   form             ; FUNCTION_{STATEMENT|EXPRESSION|EXPRESSION_STATEMENT}
   name             ; function name (a `js2-name-node', or nil if anonymous)
-  params           ; a lisp list of destructuring forms or simple name nodes
+  params           ; a Lisp list of destructuring forms or simple name nodes
   body             ; a `js2-block-node' or expression node (1.8 only)
   lp               ; position of arg-list open-paren, or nil if omitted
   rp               ; position of arg-list close-paren, or nil if omitted
@@ -3077,7 +2978,7 @@ The `params' field is a lisp list of nodes.  Each node is 
either a simple
     (unless expr
       (insert "\n"))))
 
-(defsubst js2-function-name (node)
+(defun js2-function-name (node)
   "Return function name for NODE, a `js2-function-node', or nil if anonymous."
   (and (js2-function-node-name node)
        (js2-name-node-name (js2-function-node-name node))))
@@ -3092,14 +2993,13 @@ The `params' field is a lisp list of nodes.  Each node 
is either a simple
             (:constructor nil)
             (:constructor make-js2-var-decl-node (&key (type js2-VAR)
                                                        (pos js2-token-beg)
-                                                       len
-                                                       kids
+                                                       len kids
                                                        decl-type)))
   "AST node for a variable declaration list (VAR, CONST or LET).
 The node bounds differ depending on the declaration type.  For VAR or
 CONST declarations, the bounds include the var/const keyword.  For LET
 declarations, the node begins at the position of the first child."
-  kids        ; a lisp list of `js2-var-init-node' structs.
+  kids        ; a Lisp list of `js2-var-init-node' structs.
   decl-type)  ; js2-VAR, js2-CONST or js2-LET
 
 (put 'cl-struct-js2-var-decl-node 'js2-visitor 'js2-visit-var-decl)
@@ -3133,8 +3033,7 @@ declarations, the node begins at the position of the 
first child."
             (:constructor nil)
             (:constructor make-js2-var-init-node (&key (type js2-VAR)
                                                        (pos js2-ts-cursor)
-                                                       len
-                                                       target
+                                                       len target
                                                        initializer)))
   "AST node for a variable declaration.
 The type field will be js2-CONST for a const decl."
@@ -3167,8 +3066,7 @@ The type field will be js2-CONST for a const decl."
                                                    test-expr
                                                    true-expr
                                                    false-expr
-                                                   q-pos
-                                                   c-pos)))
+                                                   q-pos c-pos)))
   "AST node for the ternary operator"
   test-expr
   true-expr
@@ -3198,10 +3096,8 @@ The type field will be js2-CONST for a const decl."
             (:constructor nil)
             (:constructor make-js2-infix-node (&key type
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    op-pos
-                                                    left
-                                                    right)))
+                                                    len op-pos
+                                                    left right)))
   "Represents infix expressions.
 Includes assignment ops like `|=', and the comma operator.
 The type field inherited from `js2-node' holds the operator."
@@ -3286,10 +3182,8 @@ The type field inherited from `js2-node' holds the 
operator."
             (:constructor nil)
             (:constructor make-js2-assign-node (&key type
                                                      (pos js2-ts-cursor)
-                                                     len
-                                                     op-pos
-                                                     left
-                                                     right)))
+                                                     len op-pos
+                                                     left right)))
   "Represents any assignment.
 The type field holds the actual assignment operator.")
 
@@ -3301,8 +3195,7 @@ The type field holds the actual assignment operator.")
             (:constructor nil)
             (:constructor make-js2-unary-node (&key type ; required
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    operand)))
+                                                    len operand)))
   "AST node type for unary operator nodes.
 The type field can be NOT, BITNOT, POS, NEG, INC, DEC,
 TYPEOF, or DELPROP.  For INC or DEC, a 'postfix node
@@ -3336,11 +3229,8 @@ property is added if the operator follows the operand."
             (:constructor nil)
             (:constructor make-js2-let-node (&key (type js2-LETEXPR)
                                                   (pos js2-token-beg)
-                                                  len
-                                                  vars
-                                                  body
-                                                  lp
-                                                  rp)))
+                                                  len vars body
+                                                  lp rp)))
   "AST node for a let expression or a let statement.
 Note that a let declaration such as let x=6, y=7 is a `js2-var-decl-node'."
   vars   ; a `js2-var-decl-node'
@@ -3386,7 +3276,7 @@ The node type is set to js2-NULL, js2-THIS, etc.")
              (t (error "Invalid keyword literal type: %d" tt))))))
 
 (defsubst js2-this-node-p (node)
-  "Return t if this node is a `js2-literal-node' of type js2-THIS."
+  "Return t if NODE is a `js2-literal-node' of type js2-THIS."
   (eq (js2-node-type node) js2-THIS))
 
 (defstruct (js2-new-node
@@ -3394,15 +3284,12 @@ The node type is set to js2-NULL, js2-THIS, etc.")
             (:constructor nil)
             (:constructor make-js2-new-node (&key (type js2-NEW)
                                                   (pos js2-token-beg)
-                                                  len
-                                                  target
-                                                  args
-                                                  initializer
-                                                  lp
-                                                  rp)))
+                                                  len target
+                                                  args initializer
+                                                  lp rp)))
   "AST node for new-expression such as new Foo()."
   target  ; an identifier or reference
-  args    ; a lisp list of argument nodes
+  args    ; a Lisp list of argument nodes
   lp      ; position of left-paren, nil if omitted
   rp      ; position of right-paren, nil if omitted
   initializer) ; experimental Rhino syntax:  optional `js2-object-node'
@@ -3479,8 +3366,7 @@ Returns 0 if NODE is nil or its identifier field is nil."
                                                      (pos js2-token-beg)
                                                      (len (- js2-ts-cursor
                                                              js2-token-beg))
-                                                     value
-                                                     flags)))
+                                                     value flags)))
   "AST node for a regular expression literal."
   value  ; the regexp string, without // delimiters
   flags) ; a string of flags, e.g. `mi'.
@@ -3521,8 +3407,7 @@ You can tell the quote type by looking at the first 
character."
             (:constructor nil)
             (:constructor make-js2-array-node (&key (type js2-ARRAYLIT)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    elems)))
+                                                    len elems)))
   "AST node for an array literal."
   elems)  ; list of expressions.  [foo,,bar] yields a nil middle element.
 
@@ -3531,7 +3416,7 @@ You can tell the quote type by looking at the first 
character."
 
 (defun js2-visit-array-node (n v)
   (dolist (e (js2-array-node-elems n))
-    (js2-visit-ast e v)))
+    (js2-visit-ast e v)))  ; Can be nil; e.g. [a, ,b].
 
 (defun js2-print-array-node (n i)
   (insert (js2-make-pad i) "[")
@@ -3546,8 +3431,8 @@ You can tell the quote type by looking at the first 
character."
                                                      len
                                                      elems)))
   "AST node for an object literal expression.
-`elems' is a list of either `js2-object-prop-node' or `js2-name-node',
-the latter represents abbreviation in destructuring expressions."
+`elems' is a list of either `js2-object-prop-node' or `js2-name-node'.
+The latter represents abbreviation in destructuring expressions."
   elems)
 
 (put 'cl-struct-js2-object-node 'js2-visitor 'js2-visit-object-node)
@@ -3567,10 +3452,8 @@ the latter represents abbreviation in destructuring 
expressions."
             (:constructor nil)
             (:constructor make-js2-object-prop-node (&key (type js2-COLON)
                                                           (pos js2-ts-cursor)
-                                                          len
-                                                          left
-                                                          right
-                                                          op-pos)))
+                                                          len left
+                                                          right op-pos)))
   "AST node for an object literal prop:value entry.
 The `left' field is the property:  a name node, string node or number node.
 The `right' field is a `js2-node' representing the initializer value.")
@@ -3589,9 +3472,7 @@ The `right' field is a `js2-node' representing the 
initializer value.")
             (:constructor nil)
             (:constructor make-js2-getter-setter-node (&key type ; GET or SET
                                                             (pos js2-ts-cursor)
-                                                            len
-                                                            left
-                                                            right)))
+                                                            len left right)))
   "AST node for a getter/setter property in an object literal.
 The `left' field is the `js2-name-node' naming the getter/setter prop.
 The `right' field is always an anonymous `js2-function-node' with a node
@@ -3614,9 +3495,7 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
             (:constructor nil)
             (:constructor make-js2-prop-get-node (&key (type js2-GETPROP)
                                                        (pos js2-ts-cursor)
-                                                       len
-                                                       left
-                                                       right)))
+                                                       len left right)))
   "AST node for a dotted property reference, e.g. foo.bar or foo().bar")
 
 (put 'cl-struct-js2-prop-get-node 'js2-visitor 'js2-visit-prop-get-node)
@@ -3637,11 +3516,8 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
             (:constructor nil)
             (:constructor make-js2-elem-get-node (&key (type js2-GETELEM)
                                                        (pos js2-ts-cursor)
-                                                       len
-                                                       target
-                                                       element
-                                                       lb
-                                                       rb)))
+                                                       len target element
+                                                       lb rb)))
   "AST node for an array index expression such as foo[bar]."
   target  ; a `js2-node' - the expression preceding the "."
   element ; a `js2-node' - the expression in brackets
@@ -3667,14 +3543,11 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
             (:constructor nil)
             (:constructor make-js2-call-node (&key (type js2-CALL)
                                                    (pos js2-ts-cursor)
-                                                   len
-                                                   target
-                                                   args
-                                                   lp
-                                                   rp)))
+                                                   len target args
+                                                   lp rp)))
   "AST node for a JavaScript function call."
   target  ; a `js2-node' evaluating to the function to call
-  args  ; a lisp list of `js2-node' arguments
+  args  ; a Lisp list of `js2-node' arguments
   lp    ; position of open-paren, or nil if missing
   rp)   ; position of close-paren, or nil if missing
 
@@ -3698,8 +3571,7 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
             (:constructor nil)
             (:constructor make-js2-yield-node (&key (type js2-YIELD)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    value)))
+                                                    len value)))
   "AST node for yield statement or expression."
   value) ; optional:  value to be yielded
 
@@ -3721,8 +3593,7 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
             (:constructor nil)
             (:constructor make-js2-paren-node (&key (type js2-LP)
                                                     (pos js2-ts-cursor)
-                                                    len
-                                                    expr)))
+                                                    len expr)))
   "AST node for a parenthesized expression.
 In particular, used when the parens are syntactically optional,
 as opposed to required parens such as those enclosing an if-conditional."
@@ -3745,16 +3616,12 @@ as opposed to required parens such as those enclosing 
an if-conditional."
             (:constructor nil)
             (:constructor make-js2-array-comp-node (&key (type js2-ARRAYCOMP)
                                                          (pos js2-ts-cursor)
-                                                         len
-                                                         result
-                                                         loops
-                                                         filter
-                                                         if-pos
-                                                         lp
-                                                         rp)))
+                                                         len result
+                                                         loops filter
+                                                         if-pos lp rp)))
   "AST node for an Array comprehension such as [[x,y] for (x in foo) for (y in 
bar)]."
   result  ; result expression (just after left-bracket)
-  loops   ; a lisp list of `js2-array-comp-loop-node'
+  loops   ; a Lisp list of `js2-array-comp-loop-node'
   filter  ; guard/filter expression
   if-pos  ; buffer pos of 'if' keyword, if present, else nil
   lp      ; buffer position of if-guard left-paren, or nil if not present
@@ -3789,14 +3656,11 @@ as opposed to required parens such as those enclosing 
an if-conditional."
             (:constructor nil)
             (:constructor make-js2-array-comp-loop-node (&key (type js2-FOR)
                                                               (pos 
js2-ts-cursor)
-                                                              len
-                                                              iterator
-                                                              object
-                                                              in-pos
+                                                              len iterator
+                                                              object in-pos
                                                               foreach-p
                                                               each-pos
-                                                              lp
-                                                              rp)))
+                                                              lp rp)))
   "AST subtree for each 'for (foo in bar)' loop in an array comprehension.")
 
 (put 'cl-struct-js2-array-comp-loop-node 'js2-visitor 
'js2-visit-array-comp-loop)
@@ -3829,8 +3693,7 @@ as opposed to required parens such as those enclosing an 
if-conditional."
             (:constructor nil)
             (:constructor make-js2-xml-node (&key (type js2-XML)
                                                   (pos js2-token-beg)
-                                                  len
-                                                  kids)))
+                                                  len kids)))
   "AST node for initial parse of E4X literals.
 The kids field is a list of XML fragments, each a `js2-string-node' or
 a `js2-xml-js-expr-node'.  Equivalent to Rhino's XmlLiteral node.")
@@ -3847,8 +3710,7 @@ a `js2-xml-js-expr-node'.  Equivalent to Rhino's 
XmlLiteral node.")
             (:constructor nil)
             (:constructor make-js2-xml-js-expr-node (&key (type js2-XML)
                                                           (pos js2-ts-cursor)
-                                                          len
-                                                          expr)))
+                                                          len expr)))
   "AST node for an embedded JavaScript {expression} in an E4X literal.
 The start and end fields correspond to the curly-braces."
   expr)  ; a `js2-expr-node' of some sort
@@ -3870,11 +3732,8 @@ The start and end fields correspond to the curly-braces."
             (:constructor nil)
             (:constructor make-js2-xml-dot-query-node (&key (type js2-DOTQUERY)
                                                             (pos js2-ts-cursor)
-                                                            op-pos
-                                                            len
-                                                            left
-                                                            right
-                                                            rp)))
+                                                            op-pos len left
+                                                            right rp)))
   "AST node for an E4X foo.(bar) filter expression.
 Note that the left-paren is automatically the character immediately
 following the dot (.) in the operator.  No whitespace is permitted
@@ -3930,10 +3789,8 @@ expression whose parent is a `js2-xml-dot-query-node'."
             (:constructor nil)
             (:constructor make-js2-xml-prop-ref-node (&key (type js2-REF_NAME)
                                                            (pos js2-token-beg)
-                                                           len
-                                                           propname
-                                                           namespace
-                                                           at-pos
+                                                           len propname
+                                                           namespace at-pos
                                                            colon-pos)))
   "AST node for an E4X XML [expr] property-ref expression.
 The JavaScript syntax is an optional @, an optional ns::, and a name.
@@ -3971,12 +3828,8 @@ expression."
             (:constructor nil)
             (:constructor make-js2-xml-elem-ref-node (&key (type 
js2-REF_MEMBER)
                                                            (pos js2-token-beg)
-                                                           len
-                                                           expr
-                                                           lb
-                                                           rb
-                                                           namespace
-                                                           at-pos
+                                                           len expr lb rb
+                                                           namespace at-pos
                                                            colon-pos)))
   "AST node for an E4X XML [expr] member-ref expression.
 Syntax:
@@ -4025,15 +3878,12 @@ end of the index expression."
             (:constructor nil)
             (:constructor make-js2-xml-start-tag-node (&key (type js2-XML)
                                                             (pos js2-ts-cursor)
-                                                            len
-                                                            name
-                                                            attrs
-                                                            kids
+                                                            len name attrs kids
                                                             empty-p)))
   "AST node for an XML start-tag.  Not currently used.
-The `kids' field is a lisp list of child content nodes."
+The `kids' field is a Lisp list of child content nodes."
   name      ; a `js2-xml-name-node'
-  attrs     ; a lisp list of `js2-xml-attr-node'
+  attrs     ; a Lisp list of `js2-xml-attr-node'
   empty-p)  ; t if this is an empty element such as <foo bar="baz"/>
 
 (put 'cl-struct-js2-xml-start-tag-node 'js2-visitor 'js2-visit-xml-start-tag)
@@ -4060,8 +3910,7 @@ The `kids' field is a lisp list of child content nodes."
             (:constructor nil)
             (:constructor make-js2-xml-end-tag-node (&key (type js2-XML)
                                                           (pos js2-ts-cursor)
-                                                          len
-                                                          name)))
+                                                          len name)))
   "AST node for an XML end-tag.  Not currently used."
   name)  ; a `js2-xml-name-node'
 
@@ -4082,9 +3931,7 @@ The `kids' field is a lisp list of child content nodes."
             (:constructor nil)
             (:constructor make-js2-xml-name-node (&key (type js2-XML)
                                                        (pos js2-ts-cursor)
-                                                       len
-                                                       namespace
-                                                       kids)))
+                                                       len namespace kids)))
   "AST node for an E4X XML name.  Not currently used.
 Any XML name can be qualified with a namespace, hence the namespace field.
 Further, any E4X name can be comprised of arbitrary JavaScript {} expressions.
@@ -4111,9 +3958,7 @@ For a simple name, the kids list has exactly one node, a 
`js2-name-node'."
             (:constructor nil)
             (:constructor make-js2-xml-pi-node (&key (type js2-XML)
                                                      (pos js2-ts-cursor)
-                                                     len
-                                                     name
-                                                     attrs)))
+                                                     len name attrs)))
   "AST node for an E4X XML processing instruction.  Not currently used."
   name   ; a `js2-xml-name-node'
   attrs) ; a list of `js2-xml-attr-node'
@@ -4139,8 +3984,7 @@ For a simple name, the kids list has exactly one node, a 
`js2-name-node'."
             (:constructor nil)
             (:constructor make-js2-xml-cdata-node (&key (type js2-XML)
                                                         (pos js2-ts-cursor)
-                                                        len
-                                                        content)))
+                                                        len content)))
   "AST node for a CDATA escape section.  Not currently used."
   content)  ; a `js2-string-node' with node-property 'quote-type 'cdata
 
@@ -4159,11 +4003,8 @@ For a simple name, the kids list has exactly one node, a 
`js2-name-node'."
             (:constructor nil)
             (:constructor make-js2-attr-node (&key (type js2-XML)
                                                    (pos js2-ts-cursor)
-                                                   len
-                                                   name
-                                                   value
-                                                   eq-pos
-                                                   quote-type)))
+                                                   len name value
+                                                   eq-pos quote-type)))
   "AST node representing a foo='bar' XML attribute value.  Not yet used."
   name   ; a `js2-xml-name-node'
   value  ; a `js2-xml-name-node'
@@ -4192,10 +4033,9 @@ For a simple name, the kids list has exactly one node, a 
`js2-name-node'."
             (:constructor nil)
             (:constructor make-js2-text-node (&key (type js2-XML)
                                                    (pos js2-ts-cursor)
-                                                   len
-                                                   content)))
+                                                   len content)))
   "AST node for an E4X XML text node.  Not currently used."
-  content)  ; a lisp list of `js2-string-node' and `js2-xml-js-expr-node'
+  content)  ; a Lisp list of `js2-string-node' and `js2-xml-js-expr-node'
 
 (put 'cl-struct-js2-xml-text-node 'js2-visitor 'js2-visit-xml-text-node)
 (put 'cl-struct-js2-xml-text-node 'js2-printer 'js2-print-xml-text-node)
@@ -4263,8 +4103,8 @@ is not a statement node."
   (substring (symbol-name (aref n 0))
              (length "cl-struct-")))
 
-(defsubst js2-node-child-list (node)
-  "Return the child list for NODE, a lisp list of nodes.
+(defun js2-node-child-list (node)
+  "Return the child list for NODE, a Lisp list of nodes.
 Works for block nodes, array nodes, obj literals, funarg lists,
 var decls and try nodes (for catch clauses).  Note that you should call
 `js2-block-node-kids' on the function body for the body statements.
@@ -4289,7 +4129,7 @@ Returns nil for zero-length child lists or unsupported 
nodes."
    (t
     nil)))
 
-(defsubst js2-node-set-child-list (node kids)
+(defun js2-node-set-child-list (node kids)
   "Set the child list for NODE to KIDS."
    (cond
     ((js2-function-node-p node)
@@ -4342,7 +4182,7 @@ a `js2-new-node' and there are no arguments or 
parentheses."
   (memq (aref node 0) js2-paren-expr-nodes))
 
 ;; Fake polymorphism... yech.
-(defsubst js2-node-lp (node)
+(defun js2-node-lp (node)
   "Return relative left-paren position for NODE, if applicable.
 For `js2-elem-get-node' structs, returns left-bracket position.
 Note that the position may be nil in the case of a parse error."
@@ -4377,7 +4217,7 @@ Note that the position may be nil in the case of a parse 
error."
     (error "Unsupported node type: %s" (js2-node-short-name node)))))
 
 ;; Fake polymorphism... blech.
-(defsubst js2-node-rp (node)
+(defun js2-node-rp (node)
   "Return relative right-paren position for NODE, if applicable.
 For `js2-elem-get-node' structs, returns right-bracket position.
 Note that the position may be nil in the case of a parse error."
@@ -4412,11 +4252,11 @@ Note that the position may be nil in the case of a 
parse error."
     (error "Unsupported node type: %s" (js2-node-short-name node)))))
 
 (defsubst js2-node-first-child (node)
-  "Returns the first element of `js2-node-child-list' for NODE."
+  "Return the first element of `js2-node-child-list' for NODE."
   (car (js2-node-child-list node)))
 
 (defsubst js2-node-last-child (node)
-  "Returns the last element of `js2-node-last-child' for NODE."
+  "Return the last element of `js2-node-last-child' for NODE."
   (car (last (js2-node-child-list node))))
 
 (defun js2-node-prev-sibling (node)
@@ -4456,9 +4296,7 @@ Returns nil if no applicable child is found."
         (beg (if (js2-function-node-p parent)
                  (js2-node-abs-pos (js2-function-node-body parent))
                (js2-node-abs-pos parent)))
-        kid
-        result
-        fn
+        kid result fn
         (continue t))
     (setq fn (if after '>= '<))
     (while (and kids continue)
@@ -4497,7 +4335,7 @@ node, or if parent links were not recorded during 
parsing."
          (js2-ast-root-p root)
          (js2-ast-root-buffer root))))
 
-(defsubst js2-block-node-push (n kid)
+(defun js2-block-node-push (n kid)
   "Push js2-node KID onto the end of js2-block-node N's child list.
 KID is always added to the -end- of the kids list.
 Function also calls `js2-node-add-children' to add the parent link."
@@ -4508,13 +4346,10 @@ Function also calls `js2-node-add-children' to add the 
parent link."
     (js2-node-add-children n kid)))
 
 (defun js2-node-string (node)
-  (let ((buf (js2-node-buffer node))
-        pos)
-    (unless buf
-      (error "No buffer available for node %s" node))
-    (with-current-buffer buf
-      (buffer-substring-no-properties (setq pos (js2-node-abs-pos node))
-                                      (+ pos (js2-node-len node))))))
+  (with-current-buffer (or (js2-node-buffer node)
+                           (error "No buffer available for node %s" node))
+    (let ((pos (js2-node-abs-pos node)))
+      (buffer-substring-no-properties pos (+ pos (js2-node-len node))))))
 
 ;; Container for storing the node we're looking for in a traversal.
 (js2-deflocal js2-discovered-node nil)
@@ -4612,8 +4447,7 @@ POS is a buffer position that defaults to current point.
 Function returns nil if POS was not in any comment node."
   (let ((ast js2-mode-ast)
         (x (or pos (point)))
-        beg
-        end)
+        beg end)
     (unless ast
       (error "No JavaScript AST available"))
     (catch 'done
@@ -4668,7 +4502,7 @@ If NODE is the ast-root, returns nil."
       (setq node (js2-node-parent node)))
     node))
 
-(defsubst js2-nested-function-p (node)
+(defun js2-nested-function-p (node)
   "Return t if NODE is a nested function, or is inside a nested function."
   (unless (js2-ast-root-p node)
     (js2-function-node-p (if (js2-function-node-p node)
@@ -4676,25 +4510,25 @@ If NODE is the ast-root, returns nil."
                            (js2-node-parent-script-or-fn
                             (js2-node-parent-script-or-fn node))))))
 
-(defsubst js2-function-param-node-p (node)
+(defun js2-function-param-node-p (node)
   "Return non-nil if NODE is a param node of a `js2-function-node'."
   (let ((parent (js2-node-parent node)))
     (and parent
          (js2-function-node-p parent)
          (memq node (js2-function-node-params parent)))))
 
-(defsubst js2-mode-shift-kids (kids start offset)
+(defun js2-mode-shift-kids (kids start offset)
   (dolist (kid kids)
     (if (> (js2-node-pos kid) start)
         (incf (js2-node-pos kid) offset))))
 
-(defsubst js2-mode-shift-children (parent start offset)
+(defun js2-mode-shift-children (parent start offset)
   "Update start-positions of all children of PARENT beyond START."
   (let ((root (js2-node-root parent)))
     (js2-mode-shift-kids (js2-node-child-list parent) start offset)
     (js2-mode-shift-kids (js2-ast-root-comments root) start offset)))
 
-(defsubst js2-node-is-descendant (node ancestor)
+(defun js2-node-is-descendant (node ancestor)
   "Return t if NODE is a descendant of ANCESTOR."
   (while (and node
               (not (eq node ancestor)))
@@ -4824,7 +4658,7 @@ You should use `js2-print-tree' instead of this function."
     (let ((tt (js2-node-type node)))
       (cond
        ;; This doubtless needs some work, since EXPR_VOID is used
-       ;; in several ways in Rhino, and I may not have caught them all.
+       ;; in several ways in Rhino and I may not have caught them all.
        ;; I'll wait for people to notice incorrect warnings.
        ((and (= tt js2-EXPR_VOID)
              (js2-expr-stmt-node-p node)) ; but not if EXPR_RESULT
@@ -4905,7 +4739,7 @@ For these node types in a statement context, the parent 
will be a
 Functions aren't included in the check."
   (memq (js2-node-type node) js2-stmt-node-types))
 
-(defsubst js2-mode-find-first-stmt (node)
+(defun js2-mode-find-first-stmt (node)
   "Search upward starting from NODE looking for a statement.
 For purposes of this function, a `js2-function-node' counts."
   (while (not (or (js2-stmt-node-p node)
@@ -4992,7 +4826,7 @@ Returns t if the function satisfies strict mode 
requirement."
                                       js2-END_YIELDS)))))
 
 (defun js2-end-check-if (node)
-  "Returns in the then and else blocks must be consistent with each other.
+  "Ensure that return usage in then/else blocks is consistent.
 If there is no else block, then the return statement can fall through.
 Returns logical OR of END_* flags"
   (let ((th (js2-if-node-then-part node))
@@ -5051,11 +4885,11 @@ Returns logical OR of END_* flags."
    rv))
 
 (defun js2-end-check-loop (node)
-  "Return statement in the loop body must be consistent. The default
-assumption for any kind of a loop is that it will eventually terminate.
-The only exception is a loop with a constant true condition. Code that
-follows such a loop is examined only if one can statically determine
-that there is a break out of the loop.
+  "Return statement in the loop body must be consistent.
+The default assumption for any kind of a loop is that it will eventually
+terminate.  The only exception is a loop with a constant true condition.
+Code that follows such a loop is examined only if one can determine
+statically that there is a break out of the loop.
 
     for(... ; ... ; ...) {}
     for(... in ... ) {}
@@ -5238,7 +5072,7 @@ Signals an error if it's not a recognized token."
   (or (gethash sym js2-token-codes)
       (error "Invalid token symbol: %s " sym)))  ; signal code bug
 
-(defsubst js2-report-scan-error (msg &optional no-throw beg len)
+(defun js2-report-scan-error (msg &optional no-throw beg len)
   (setq js2-token-end js2-ts-cursor)
   (js2-report-error msg nil
                     (or beg js2-token-beg)
@@ -5246,7 +5080,7 @@ Signals an error if it's not a recognized token."
   (unless no-throw
     (throw 'return js2-ERROR)))
 
-(defsubst js2-get-string-from-buffer ()
+(defun js2-get-string-from-buffer ()
   "Reverse the char accumulator and return it as a string."
   (setq js2-token-end js2-ts-cursor)
   (if js2-ts-string-buffer
@@ -5267,7 +5101,7 @@ Signals an error if it's not a recognized token."
 
 ;; Rhino distinguishes \r and \n line endings.  We don't need to
 ;; because we only scan from Emacs buffers, which always use \n.
-(defsubst js2-get-char ()
+(defun js2-get-char ()
   "Read and return the next character from the input buffer.
 Increments `js2-ts-lineno' if the return value is a newline char.
 Updates `js2-ts-cursor' to the point after the returned char.
@@ -5288,7 +5122,7 @@ Also updates `js2-ts-hit-eof' and `js2-ts-line-start' as 
needed."
       ;; TODO:  skip over format characters
       c)))
 
-(defsubst js2-read-unicode-escape ()
+(defun js2-read-unicode-escape ()
   "Read a \\uNNNN sequence from the input.
 Assumes the ?\ and ?u have already been read.
 Returns the unicode character, or nil if it wasn't a valid character.
@@ -5304,7 +5138,7 @@ Doesn't change the values of any scanner variables."
       (if (string-match "[a-zA-Z0-9]\\{4\\}" s)
           (read (concat "?\\u" s))))))
 
-(defsubst js2-match-char (test)
+(defun js2-match-char (test)
   "Consume and return next character if it matches TEST, a character.
 Returns nil and consumes nothing if TEST is not the next character."
   (let ((c (js2-get-char)))
@@ -5313,19 +5147,19 @@ Returns nil and consumes nothing if TEST is not the 
next character."
       (js2-unget-char)
       nil)))
 
-(defsubst js2-peek-char ()
+(defun js2-peek-char ()
   (prog1
       (js2-get-char)
     (js2-unget-char)))
 
-(defsubst js2-java-identifier-start-p (c)
+(defun js2-java-identifier-start-p (c)
   (or
    (memq c '(?$ ?_))
    (js2-char-uppercase-p c)
    (js2-char-lowercase-p c)))
 
-(defsubst js2-java-identifier-part-p (c)
-  "Implementation of java.lang.Character.isJavaIdentifierPart()"
+(defun js2-java-identifier-part-p (c)
+  "Implementation of java.lang.Character.isJavaIdentifierPart()."
   ;; TODO:  make me Unicode-friendly.  See comments above.
   (or
    (memq c '(?$ ?_))
@@ -5333,7 +5167,7 @@ Returns nil and consumes nothing if TEST is not the next 
character."
    (js2-char-lowercase-p c)
    (and (>= c ?0) (<= c ?9))))
 
-(defsubst js2-alpha-p (c)
+(defun js2-alpha-p (c)
   (cond ((and (<= ?A c) (<= c ?Z)) t)
         ((and (<= ?a c) (<= c ?z)) t)
         (t nil)))
@@ -5341,7 +5175,7 @@ Returns nil and consumes nothing if TEST is not the next 
character."
 (defsubst js2-digit-p (c)
   (and (<= ?0 c) (<= c ?9)))
 
-(defsubst js2-js-space-p (c)
+(defun js2-js-space-p (c)
   (if (<= c 127)
       (memq c '(#x20 #x9 #xB #xC #xD))
     (or
@@ -5351,8 +5185,8 @@ Returns nil and consumes nothing if TEST is not the next 
character."
 
 (defconst js2-eol-chars (list js2-EOF_CHAR ?\n ?\r))
 
-(defsubst js2-skip-line ()
-  "Skip to end of line"
+(defun js2-skip-line ()
+  "Skip to end of line."
   (let (c)
     (while (not (memq (setq c (js2-get-char)) js2-eol-chars)))
     (js2-unget-char)
@@ -5360,15 +5194,13 @@ Returns nil and consumes nothing if TEST is not the 
next character."
 
 (defun js2-init-scanner (&optional buf line)
   "Create token stream for BUF starting on LINE.
-BUF defaults to current-buffer and line defaults to 1.
+BUF defaults to `current-buffer' and LINE defaults to 1.
 
 A buffer can only have one scanner active at a time, which yields
 dramatically simpler code than using a defstruct.  If you need to
 have simultaneous scanners in a buffer, copy the regions to scan
 into temp buffers."
-  (save-excursion
-    (when buf
-      (set-buffer buf))
+  (with-current-buffer (or buf (current-buffer))
     (setq js2-ts-dirty-line nil
           js2-ts-regexp-flags nil
           js2-ts-string ""
@@ -5483,7 +5315,7 @@ The values are default faces to use for highlighting the 
keywords.")
     table)
   "JavaScript reserved words by name, mapped to 'js2-RESERVED.")
 
-(defsubst js2-collect-string (buf)
+(defun js2-collect-string (buf)
   "Convert BUF, a list of chars, to a string.
 Reverses BUF before converting."
   (cond
@@ -5513,7 +5345,7 @@ Updates `js2-token-end' accordingly."
   (setq js2-token-end js2-ts-cursor)
   (throw 'return token))
 
-(defsubst js2-x-digit-to-int (c accumulator)
+(defun js2-x-digit-to-int (c accumulator)
   "Build up a hex number.
 If C is a hexadecimal digit, return ACCUMULATOR * 16 plus
 corresponding number.  Otherwise return -1."
@@ -5538,21 +5370,9 @@ corresponding number.  Otherwise return -1."
 
 (defun js2-get-token ()
   "Return next JavaScript token, an int such as js2-RETURN."
-  (let (c
-        c1
-        identifier-start
-        is-unicode-escape-start
-        contains-escape
-        escape-val
-        escape-start
-        str
-        result
-        base
-        is-integer
-        quote-char
-        val
-        look-for-slash
-        continue)
+  (let (c c1 identifier-start is-unicode-escape-start
+        contains-escape escape-val escape-start str result base
+        is-integer quote-char val look-for-slash continue)
     (catch 'return
       (while t
         ;; Eat whitespace, possibly sensitive to newlines.
@@ -5969,8 +5789,7 @@ corresponding number.  Otherwise return -1."
 
 (defun js2-read-regexp (start-token)
   "Called by parser when it gets / or /= in literal context."
-  (let (c
-        err
+  (let (c err
         in-class  ; inside a '[' .. ']' character-class
         flags
         (continue t))
@@ -6028,7 +5847,7 @@ corresponding number.  Otherwise return -1."
   (js2-unget-char)
   (js2-get-next-xml-token))
 
-(defsubst js2-xml-discard-string ()
+(defun js2-xml-discard-string ()
   "Throw away the string in progress and flag an XML parse error."
   (setq js2-ts-string-buffer nil
         js2-ts-string nil)
@@ -6123,8 +5942,8 @@ corresponding number.  Otherwise return -1."
                         (t
                          (unless (js2-read-entity)
                            (throw 'return js2-ERROR))))
-                      ;; allow bare CDATA section
-                      ;; ex) let xml = <![CDATA[ foo bar baz ]]>;
+                      ;; Allow bare CDATA section, e.g.:
+                      ;;   let xml = <![CDATA[ foo bar baz ]]>;
                       (when (zerop js2-ts-xml-open-tags-count)
                         (throw 'return js2-XMLEND)))
                      (??
@@ -6237,7 +6056,7 @@ corresponding number.  Otherwise return -1."
 
 ;;; Highlighting
 
-(defsubst js2-set-face (beg end face &optional record)
+(defun js2-set-face (beg end face &optional record)
   "Fontify a region.  If RECORD is non-nil, record for later."
   (when (plusp js2-highlight-level)
     (setq beg (min (point-max) beg)
@@ -6248,7 +6067,7 @@ corresponding number.  Otherwise return -1."
         (push (list beg end face) js2-mode-fontifications)
       (put-text-property beg end 'font-lock-face face))))
 
-(defsubst js2-set-kid-face (pos kid len face)
+(defun js2-set-kid-face (pos kid len face)
   "Set-face on a child node.
 POS is absolute buffer position of parent.
 KID is the child node.
@@ -6366,7 +6185,7 @@ Shown at or above `js2-highlight-level' 2.")
   "Built-in functions defined by Ecma-262 and SpiderMonkey extensions.
 Shown at or above `js2-highlight-level' 3.")
 
-(defsubst js2-parse-highlight-prop-get (parent target prop call-p)
+(defun js2-parse-highlight-prop-get (parent target prop call-p)
   (let ((target-name (and target
                           (js2-name-node-p target)
                           (js2-name-node-name target)))
@@ -6374,8 +6193,7 @@ Shown at or above `js2-highlight-level' 3.")
         (level1 (>= js2-highlight-level 1))
         (level2 (>= js2-highlight-level 2))
         (level3 (>= js2-highlight-level 3))
-        pos
-        face)
+        pos face)
     (when level2
       (if call-p
           (cond
@@ -6583,7 +6401,7 @@ of a simple name.  Called before EXPR has a parent node."
   "\\(</?\\)\\([a-zA-Z]+\\)\\s-*\\(/?>\\)"
   "Matches a simple (no attributes) html start- or end-tag.")
 
-(defsubst js2-jsdoc-highlight-helper ()
+(defun js2-jsdoc-highlight-helper ()
   (js2-set-face (match-beginning 1)
                 (match-end 1)
                 'js2-jsdoc-tag-face)
@@ -6759,7 +6577,7 @@ it is considered declared."
 ;; that isn't a valid JavaScript identifier, because you might make foo
 ;; a function and then start setting properties on it that are also functions.
 
-(defsubst js2-prop-node-name (node)
+(defun js2-prop-node-name (node)
   "Return the name of a node that may be a property-get/property-name.
 If NODE is not a valid name-node, string-node or integral number-node,
 returns nil.  Otherwise returns the string name/value of the node."
@@ -6774,7 +6592,7 @@ returns nil.  Otherwise returns the string name/value of 
the node."
    ((js2-this-node-p node)
     "this")))
 
-(defsubst js2-node-qname-component (node)
+(defun js2-node-qname-component (node)
   "Return the name of this node, if it contributes to a qname.
 Returns nil if the node doesn't contribute."
   (copy-sequence
@@ -6783,7 +6601,7 @@ Returns nil if the node doesn't contribute."
                 (js2-function-node-name node))
            (js2-name-node-name (js2-function-node-name node))))))
 
-(defsubst js2-record-imenu-entry (fn-node qname pos)
+(defun js2-record-imenu-entry (fn-node qname pos)
   "Add an entry to `js2-imenu-recorder'.
 FN-NODE should be the current item's function node.
 
@@ -6874,7 +6692,7 @@ we append the property name to QNAME, then call 
`js2-record-imenu-entry'."
                                      (append qname (list (js2-infix-node-left 
e)))
                                      (+ pos (js2-node-pos right)))))))))
 
-(defsubst js2-node-top-level-decl-p (node)
+(defun js2-node-top-level-decl-p (node)
   "Return t if NODE's name is defined in the top-level scope.
 Also returns t if NODE's name is not defined in any scope, since it implies
 that it's an external variable, which must also be in the top-level scope."
@@ -6890,7 +6708,7 @@ that it's an external variable, which must also be in the 
top-level scope."
       (js2-ast-root-p defining-scope))
      (t t))))
 
-(defsubst js2-wrapper-function-p (node)
+(defun js2-wrapper-function-p (node)
   "Returns t if NODE is a function expression that's immediately invoked.
 NODE must be `js2-function-node'."
   (let ((parent (js2-node-parent node)))
@@ -6974,7 +6792,7 @@ For instance, processing a nested scope requires a parent 
function node."
 ;; The sub-alist entries immediately follow INDEX-NAME, the head of the list.
 
 (defun js2-treeify (lst)
-  "Convert (a b c d) to (a ((b ((c d)))))"
+  "Convert (a b c d) to (a ((b ((c d)))))."
   (if (null (cddr lst))  ; list length <= 2
       lst
     (list (car lst) (list (js2-treeify (cdr lst))))))
@@ -7088,7 +6906,7 @@ is only true until the node is added to its parent; i.e., 
while parsing."
   (+ (js2-node-pos n)
      (js2-node-len n)))
 
-(defsubst js2-record-comment ()
+(defun js2-record-comment ()
   "Record a comment in `js2-scanned-comments'."
   (push (make-js2-comment-node :len (- js2-token-end js2-token-beg)
                                :format js2-ts-comment-type)
@@ -7103,8 +6921,8 @@ is only true until the node is added to its parent; i.e., 
while parsing."
 
 ;; This function is called depressingly often, so it should be fast.
 ;; Most of the time it's looking at the same token it peeked before.
-(defsubst js2-peek-token ()
-  "Returns the next token without consuming it.
+(defun js2-peek-token ()
+  "Return the next token without consuming it.
 If previous token was consumed, calls scanner to get new token.
 If previous token was -not- consumed, returns it (idempotent).
 
@@ -7149,7 +6967,7 @@ The flags, if any, are saved in 
`js2-current-flagged-token'."
           (js2-record-face 'font-lock-constant-face))))
       tt)))  ; return unflagged token
 
-(defsubst js2-peek-flagged-token ()
+(defun js2-peek-flagged-token ()
   "Returns the current token along with any flags set for it."
   (js2-peek-token)
   js2-current-flagged-token)
@@ -7157,17 +6975,17 @@ The flags, if any, are saved in 
`js2-current-flagged-token'."
 (defsubst js2-consume-token ()
   (setq js2-current-flagged-token js2-EOF))
 
-(defsubst js2-next-token ()
+(defun js2-next-token ()
   (prog1
       (js2-peek-token)
     (js2-consume-token)))
 
-(defsubst js2-next-flagged-token ()
+(defun js2-next-flagged-token ()
   (js2-peek-token)
   (prog1 js2-current-flagged-token
     (js2-consume-token)))
 
-(defsubst js2-match-token (match)
+(defun js2-match-token (match)
   "Consume and return t if next token matches MATCH, a bytecode.
 Returns nil and consumes nothing if MATCH is not the next token."
   (if (/= (js2-peek-token) match)
@@ -7175,13 +6993,13 @@ Returns nil and consumes nothing if MATCH is not the 
next token."
     (js2-consume-token)
     t))
 
-(defsubst js2-valid-prop-name-token (tt)
+(defun js2-valid-prop-name-token (tt)
   (or (= tt js2-NAME)
       (and js2-allow-keywords-as-property-names
            (plusp tt)
            (aref js2-kwd-tokens tt))))
 
-(defsubst js2-match-prop-name ()
+(defun js2-match-prop-name ()
   "Consume token and return t if next token is a valid property name.
 It's valid if it's a js2-NAME, or `js2-allow-keywords-as-property-names'
 is non-nil and it's a keyword token."
@@ -7191,13 +7009,13 @@ is non-nil and it's a keyword token."
         t)
     nil))
 
-(defsubst js2-must-match-prop-name (msg-id &optional pos len)
+(defun js2-must-match-prop-name (msg-id &optional pos len)
   (if (js2-match-prop-name)
       t
     (js2-report-error msg-id nil pos len)
     nil))
 
-(defsubst js2-peek-token-or-eol ()
+(defun js2-peek-token-or-eol ()
   "Return js2-EOL if the current token immediately follows a newline.
 Else returns the current token.  Used in situations where we don't
 consider certain token types valid if they are preceded by a newline.
@@ -7209,11 +7027,11 @@ same line as its operand."
         js2-EOL
       tt)))
 
-(defsubst js2-set-check-for-label ()
+(defun js2-set-check-for-label ()
   (assert (= (logand js2-current-flagged-token js2-clear-ti-mask) js2-NAME))
   (js2-set-flag js2-current-flagged-token js2-ti-check-label))
 
-(defsubst js2-must-match (token msg-id &optional pos len)
+(defun js2-must-match (token msg-id &optional pos len)
   "Match next token to token code TOKEN, or record a syntax error.
 MSG-ID is the error message to report if the match fails.
 Returns t on match, nil if no match."
@@ -7225,11 +7043,11 @@ Returns t on match, nil if no match."
 (defsubst js2-inside-function ()
   (plusp js2-nesting-of-function))
 
-(defsubst js2-set-requires-activation ()
+(defun js2-set-requires-activation ()
   (if (js2-function-node-p js2-current-script-or-fn)
       (setf (js2-function-node-needs-activation js2-current-script-or-fn) t)))
 
-(defsubst js2-check-activation-name (name token)
+(defun js2-check-activation-name (name token)
   (when (js2-inside-function)
     ;; skip language-version 1.2 check from Rhino
     (if (or (string= "arguments" name)
@@ -7237,15 +7055,15 @@ Returns t on match, nil if no match."
                  (gethash name js2-compiler-activation-names)))
         (js2-set-requires-activation))))
 
-(defsubst js2-set-is-generator ()
+(defun js2-set-is-generator ()
   (if (js2-function-node-p js2-current-script-or-fn)
       (setf (js2-function-node-is-generator js2-current-script-or-fn) t)))
 
-(defsubst js2-must-have-xml ()
+(defun js2-must-have-xml ()
   (unless js2-compiler-xml-available
     (js2-report-error "msg.XML.not.available")))
 
-(defsubst js2-push-scope (scope)
+(defun js2-push-scope (scope)
   "Push SCOPE, a `js2-scope', onto the lexical scope chain."
   (assert (js2-scope-p scope))
   (assert (null (js2-scope-parent-scope scope)))
@@ -7257,7 +7075,7 @@ Returns t on match, nil if no match."
   (setq js2-current-scope
         (js2-scope-parent-scope js2-current-scope)))
 
-(defsubst js2-enter-loop (loop-node)
+(defun js2-enter-loop (loop-node)
   (push loop-node js2-loop-set)
   (push loop-node js2-loop-and-switch-set)
   (js2-push-scope loop-node)
@@ -7270,7 +7088,7 @@ Returns t on match, nil if no match."
           (js2-label-node-loop (car (js2-labeled-stmt-node-labels
                                      js2-labeled-stmt))) loop-node)))
 
-(defsubst js2-exit-loop ()
+(defun js2-exit-loop ()
   (pop js2-loop-set)
   (pop js2-loop-and-switch-set)
   (js2-pop-scope))
@@ -7282,7 +7100,7 @@ Returns t on match, nil if no match."
   (pop js2-loop-and-switch-set))
 
 (defun js2-parse (&optional buf cb)
-  "Tells the js2 parser to parse a region of JavaScript.
+  "Tell the js2 parser to parse a region of JavaScript.
 
 BUF is a buffer or buffer name containing the code to parse.
 Call `narrow-to-region' first to parse only part of the buffer.
@@ -7317,8 +7135,7 @@ leaving a statement, an expression, or a function 
definition."
         (case-fold-search nil)
         ast)
     (message nil)  ; clear any error message from previous parse
-    (save-excursion
-      (when buf (set-buffer buf))
+    (with-current-buffer (or buf (current-buffer))
       (setq js2-scanned-comments nil
             js2-parsed-errors nil
             js2-parsed-warnings nil
@@ -7326,7 +7143,7 @@ leaving a statement, an expression, or a function 
definition."
             js2-imenu-function-map nil
             js2-label-set nil)
       (js2-init-scanner)
-      (setq ast (js2-with-unmodifying-text-property-changes
+      (setq ast (with-silent-modifications
                   (js2-do-parse)))
       (unless js2-ts-hit-eof
         (js2-report-error "msg.got.syntax.errors" (length js2-parsed-errors)))
@@ -7479,7 +7296,7 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
         (js2-node-add-children fn-node p)
         (push p (js2-function-node-params fn-node))))))
 
-(defsubst js2-check-inconsistent-return-warning (fn-node name)
+(defun js2-check-inconsistent-return-warning (fn-node name)
   "Possibly show inconsistent-return warning.
 Last token scanned is the close-curly for the function body."
   (when (and js2-mode-show-strict-warnings
@@ -7500,11 +7317,7 @@ Last token scanned is the close-curly for the function 
body."
 (defun js2-parse-function (function-type)
   "Function parser.  FUNCTION-TYPE is a symbol."
   (let ((pos js2-token-beg)  ; start of 'function' keyword
-        name
-        name-beg
-        name-end
-        fn-node
-        lp
+        name name-beg name-end fn-node lp
         (synthetic-type function-type)
         member-expr-node)
     ;; parse function name, expression, or non-name (anonymous)
@@ -7661,7 +7474,7 @@ node are given relative start positions and correct 
lengths."
     parsers)
   "A vector mapping token types to parser functions.")
 
-(defsubst js2-parse-warn-missing-semi (beg end)
+(defun js2-parse-warn-missing-semi (beg end)
   (and js2-mode-show-strict-warnings
        js2-strict-missing-semi-warning
        (js2-add-strict-warning
@@ -7752,12 +7565,7 @@ Return value is a list (EXPR LP RP), with absolute paren 
positions."
 (defun js2-parse-if ()
   "Parser for if-statement.  Last matched token must be js2-IF."
   (let ((pos js2-token-beg)
-        cond
-        if-true
-        if-false
-        else-pos
-        end
-        pn)
+        cond if-true if-false else-pos end pn)
     (js2-consume-token)
     (setq cond (js2-parse-condition)
           if-true (js2-parse-statement)
@@ -7780,17 +7588,8 @@ Return value is a list (EXPR LP RP), with absolute paren 
positions."
 (defun js2-parse-switch ()
   "Parser for if-statement.  Last matched token must be js2-SWITCH."
   (let ((pos js2-token-beg)
-        tt
-        pn
-        discriminant
-        has-default
-        case-expr
-        case-node
-        case-pos
-        cases
-        stmt
-        lp
-        rp)
+        tt pn discriminant has-default case-expr case-node
+        case-pos cases stmt lp rp)
     (js2-consume-token)
     (if (js2-must-match js2-LP "msg.no.paren.switch")
         (setq lp js2-token-beg))
@@ -7848,8 +7647,7 @@ Return value is a list (EXPR LP RP), with absolute paren 
positions."
   "Parser for while-statement.  Last matched token must be js2-WHILE."
   (let ((pos js2-token-beg)
         (pn (make-js2-while-node))
-        cond
-        body)
+        cond body)
     (js2-consume-token)
     (js2-enter-loop pn)
     (unwind-protect
@@ -7869,9 +7667,7 @@ Return value is a list (EXPR LP RP), with absolute paren 
positions."
   "Parser for do-statement.  Last matched token must be js2-DO."
   (let ((pos js2-token-beg)
         (pn (make-js2-do-node))
-        cond
-        body
-        end)
+        cond body end)
     (js2-consume-token)
     (js2-enter-loop pn)
     (unwind-protect
@@ -7899,19 +7695,11 @@ Return value is a list (EXPR LP RP), with absolute 
paren positions."
   "Parser for for-statement.  Last matched token must be js2-FOR.
 Parses for, for-in, and for each-in statements."
   (let ((for-pos js2-token-beg)
-        pn
-        is-for-each
-        is-for-in
-        in-pos
-        each-pos
-        tmp-pos
+        pn is-for-each is-for-in in-pos each-pos tmp-pos
         init  ; Node init is also foo in 'foo in object'
         cond  ; Node cond is also object in 'foo in object'
         incr  ; 3rd section of for-loop initializer
-        body
-        tt
-        lp
-        rp)
+        body tt lp rp)
     (js2-consume-token)
     ;; See if this is a for each () instead of just a for ()
     (when (js2-match-token js2-NAME)
@@ -8095,8 +7883,7 @@ Parses for, for-in, and for each-in statements."
 (defun js2-parse-throw ()
   "Parser for throw-statement.  Last matched token must be js2-THROW."
   (let ((pos js2-token-beg)
-        expr
-        pn)
+        expr pn)
     (js2-consume-token)
     (if (= (js2-peek-token-or-eol) js2-EOL)
         ;; ECMAScript does not allow new lines before throw expression,
@@ -8109,7 +7896,7 @@ Parses for, for-in, and for each-in statements."
     (js2-node-add-children pn expr)
     pn))
 
-(defsubst js2-match-jump-label-name (label-name)
+(defun js2-match-jump-label-name (label-name)
   "If break/continue specified a label, return that label's labeled stmt.
 Returns the corresponding `js2-labeled-stmt-node', or if LABEL-NAME
 does not match an existing label, reports an error and returns nil."
@@ -8205,8 +7992,7 @@ does not match an existing label, reports an error and 
returns nil."
 Last matched token must be js2-CONST or js2-VAR."
   (let ((tt (js2-peek-token))
         (pos js2-token-beg)
-        expr
-        pn)
+        expr pn)
     (js2-consume-token)
     (setq expr (js2-parse-variables tt js2-token-beg)
           pn (make-js2-expr-stmt-node :pos pos
@@ -8215,7 +8001,7 @@ Last matched token must be js2-CONST or js2-VAR."
     (js2-node-add-children pn expr)
     pn))
 
-(defsubst js2-wrap-with-expr-stmt (pos expr &optional add-child)
+(defun js2-wrap-with-expr-stmt (pos expr &optional add-child)
   (let ((pn (make-js2-expr-stmt-node :pos pos
                                      :len (js2-node-len expr)
                                      :type (if (js2-inside-function)
@@ -8230,8 +8016,7 @@ Last matched token must be js2-CONST or js2-VAR."
   "Parser for let-statement.  Last matched token must be js2-LET."
   (js2-consume-token)
   (let ((pos js2-token-beg)
-        expr
-        pn)
+        expr pn)
     (if (= (js2-peek-token) js2-LP)
         ;; let expression in statement context
         (setq expr (js2-parse-let pos 'statement)
@@ -8261,9 +8046,7 @@ but not BEFORE."
         (end js2-token-end)
         (before js2-end-flags)
         (inside-function (js2-inside-function))
-        e
-        ret
-        name)
+        e ret name)
     (unless inside-function
       (js2-report-error (if (eq tt js2-RETURN)
                             "msg.bad.return"
@@ -8323,7 +8106,7 @@ but not BEFORE."
 
 (defun js2-parse-block ()
   "Parser for a curly-delimited statement block.
-Last token matched must be js2-LC."
+Last token matched must be `js2-LC'."
   (let ((pos js2-token-beg)
         (pn (make-js2-scope)))
     (js2-consume-token)
@@ -8336,10 +8119,10 @@ Last token matched must be js2-LC."
       (js2-pop-scope))
     pn))
 
-;; for js2-ERROR too, to have a node for error recovery to work on
+;; For `js2-ERROR' too, to have a node for error recovery to work on.
 (defun js2-parse-semi ()
   "Parse a statement or handle an error.
-Last matched token is js-SEMI or js-ERROR."
+Last matched token is `js2-SEMI' or `js2-ERROR'."
   (let ((tt (js2-peek-token)) pos len)
     (js2-consume-token)
     (if (eq tt js2-SEMI)
@@ -8403,10 +8186,7 @@ up any following labels and the next non-label statement 
into a
 expression and return it wrapped in a `js2-expr-stmt-node'."
   (let ((pos js2-token-beg)
         (end js2-token-end)
-        expr
-        stmt
-        pn
-        bundle
+        expr stmt pn bundle
         (continue t))
     ;; set check for label and call down to `js2-parse-primary-expr'
     (js2-set-check-for-label)
@@ -8458,14 +8238,7 @@ in the first variable declaration.
 Returns the parsed `js2-var-decl-node' expression node."
   (let* ((result (make-js2-var-decl-node :decl-type decl-type
                                          :pos pos))
-         destructuring
-         kid-pos
-         tt
-         init
-         name
-         end
-         nbeg nend
-         vi
+         destructuring kid-pos tt init name end nbeg nend vi
          (continue t))
     ;; Example:
     ;; var foo = {a: 1, b: 2}, bar = [3, 4];
@@ -8556,7 +8329,7 @@ by `js2-parse-variables'."
       (js2-pop-scope))
     pn))
 
-(defsubst js2-define-new-symbol (decl-type name node &optional scope)
+(defun js2-define-new-symbol (decl-type name node &optional scope)
   (js2-scope-put-symbol (or scope js2-current-scope)
                         name
                         (make-js2-symbol decl-type name node)))
@@ -8632,10 +8405,7 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
 (defun js2-parse-assign-expr ()
   (let ((tt (js2-peek-token))
         (pos js2-token-beg)
-        pn
-        left
-        right
-        op-pos)
+        pn left right op-pos)
     (if (= tt js2-YIELD)
         (js2-parse-return-or-yield tt t)
       ;; not yield - parse assignment expression
@@ -8825,7 +8595,7 @@ or a `js2-node' struct if it has already been parsed."
         (setq continue nil)))
     pn))
 
-(defsubst js2-make-unary (type parser &rest args)
+(defun js2-make-unary (type parser &rest args)
   "Make a unary node of type TYPE.
 PARSER is either a node (for postfix operators) or a function to call
 to parse the operand (for prefix operators)."
@@ -8851,7 +8621,7 @@ to parse the operand (for prefix operators)."
   (list js2-NAME js2-GETPROP js2-GETELEM js2-GET_REF js2-CALL)
   "Node types that can be the operand of a ++ or -- operator.")
 
-(defsubst js2-check-bad-inc-dec (tt beg end unary)
+(defun js2-check-bad-inc-dec (tt beg end unary)
   (unless (memq (js2-node-type (js2-unary-node-operand unary))
                 js2-incrementable-node-types)
     (js2-report-error (if (= tt js2-INC)
@@ -8916,11 +8686,7 @@ mode or codegen mode, and generate the appropriate 
rewritten AST.
 IDE mode uses a rich AST that models the XML structure.  Codegen mode
 just concatenates everything and makes a new XML or XMLList out of it."
   (let ((tt (js2-get-first-xml-token))
-        pn-xml
-        pn
-        expr
-        kids
-        expr-pos
+        pn-xml pn expr kids expr-pos
         (continue t)
         (first-token t))
     (when (not (or (= tt js2-XML) (= tt js2-XMLEND)))
@@ -8965,7 +8731,7 @@ just concatenates everything and makes a new XML or 
XMLList out of it."
 
 
 (defun js2-parse-argument-list ()
-  "Parse an argument list and return it as a lisp list of nodes.
+  "Parse an argument list and return it as a Lisp list of nodes.
 Returns the list in reverse order.  Consumes the right-paren token."
   (let (result)
     (unless (js2-match-token js2-RP)
@@ -8980,14 +8746,7 @@ Returns the list in reverse order.  Consumes the 
right-paren token."
 
 (defun js2-parse-member-expr (&optional allow-call-syntax)
   (let ((tt (js2-peek-token))
-        pn
-        pos
-        target
-        args
-        beg
-        end
-        init
-        tail)
+        pn pos target args beg end init tail)
     (if (/= tt js2-NEW)
         (setq pn (js2-parse-primary-expr))
       ;; parse a 'new' expression
@@ -9050,9 +8809,7 @@ Returns an expression tree that includes PN, the parent 
node."
   "Parse a dot-query expression, e.g. foo.bar.(@name == 2)
 Last token parsed must be `js2-DOTQUERY'."
   (let ((pos (js2-node-pos pn))
-        op-pos
-        expr
-        end)
+        op-pos expr end)
     (js2-consume-token)
     (js2-must-have-xml)
     (js2-set-requires-activation)
@@ -9077,8 +8834,7 @@ Last token parsed must be `js2-DOTQUERY'."
 Last token parsed must be `js2-RB'."
   (let ((lb js2-token-beg)
         (pos (js2-node-pos pn))
-        rb
-        expr)
+        rb expr)
     (js2-consume-token)
     (setq expr (js2-parse-expr))
     (if (js2-must-match js2-RB "msg.no.bracket.index")
@@ -9209,10 +8965,7 @@ operator, or the name is followed by ::.  For a plain 
name, returns a
   (let ((pos (or at-pos js2-token-beg))
         colon-pos
         (name (js2-create-name-node t js2-current-token))
-        ns
-        tt
-        ref
-        pn)
+        ns tt ref pn)
     (catch 'return
       (when (js2-match-token js2-COLONCOLON)
         (setq ns name
@@ -9266,12 +9019,12 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
                                           :rb (js2-relpos rb pos)))
       (js2-node-add-children pn namespace expr))))
 
-(defsubst js2-parse-primary-expr-lhs ()
+(defun js2-parse-primary-expr-lhs ()
   (let ((js2-is-in-lhs t))
     (js2-parse-primary-expr)))
 
 (defun js2-parse-primary-expr ()
-  "Parses a literal (leaf) expression of some sort.
+  "Parse a literal (leaf) expression of some sort.
 Includes complex literals such as functions, object-literals,
 array-literals, array comprehensions and regular expressions."
   (let ((tt-flagged (js2-next-flagged-token))
@@ -9371,7 +9124,7 @@ array-literals, array comprehensions and regular 
expressions."
           (js2-record-name-node node))
       node)))
 
-(defsubst js2-parse-warn-trailing-comma (msg pos elems comma-pos)
+(defun js2-parse-warn-trailing-comma (msg pos elems comma-pos)
   (js2-add-strict-warning
    msg nil
    ;; back up from comma to beginning of line or array/objlit
@@ -9388,10 +9141,7 @@ array-literals, array comprehensions and regular 
expressions."
   (let ((pos js2-token-beg)
         (end js2-token-end)
         (after-lb-or-comma t)
-        after-comma
-        tt
-        elems
-        pn
+        after-comma tt elems pn
         (continue t))
     (unless js2-is-in-lhs
         (js2-push-scope (make-js2-scope))) ; for array comp
@@ -9459,13 +9209,7 @@ array-literals, array comprehensions and regular 
expressions."
 EXPR is the first expression after the opening left-bracket.
 POS is the beginning of the LB token preceding EXPR.
 We should have just parsed the 'for' keyword before calling this function."
-  (let (loops
-        loop
-        first
-        prev
-        filter
-        if-pos
-        result)
+  (let (loops loop first prev filter if-pos result)
     (while (= (js2-peek-token) js2-FOR)
       (let ((prev (car loops))) ; rearrange scope chain
         (push (setq loop (js2-parse-array-comp-loop)) loops)
@@ -9499,14 +9243,7 @@ We should have just parsed the 'for' keyword before 
calling this function."
 Last token peeked should be the initial FOR."
   (let ((pos js2-token-beg)
         (pn (make-js2-array-comp-loop-node))
-        tt
-        iter
-        obj
-        foreach-p
-        in-pos
-        each-pos
-        lp
-        rp)
+        tt iter obj foreach-p in-pos each-pos lp rp)
     (assert (= (js2-next-token) js2-FOR))  ; consumes token
     (js2-push-scope pn)
     (unwind-protect
@@ -9557,15 +9294,13 @@ Last token peeked should be the initial FOR."
 
 (defun js2-parse-object-literal ()
   (let ((pos js2-token-beg)
-        tt
-        elems
-        result
-        after-comma
+        tt elems result after-comma
         (continue t))
     (while continue
       (setq tt (js2-peek-token))
       (cond
-       ;; {foo: ...}, {'foo': ...}, {foo, bar, ...}, {get foo() {...}}, or 
{set foo(x) {...}}
+       ;; {foo: ...}, {'foo': ...}, {foo, bar, ...},
+       ;; {get foo() {...}}, or {set foo(x) {...}}
        ((or (js2-valid-prop-name-token tt)
             (= tt js2-STRING))
         (setq after-comma nil
@@ -9677,8 +9412,7 @@ POS is the start position of the `get' or `set' keyword.
 PROP is the `js2-name-node' representing the property name.
 GET-P is non-nil if the keyword was `get'."
   (let ((type (if get-p js2-GET js2-SET))
-        result
-        end
+        result end
         (fn (js2-parse-function 'FUNCTION_EXPRESSION)))
     ;; it has to be an anonymous function, as we already parsed the name
     (if (/= (js2-node-type fn) js2-FUNCTION)
@@ -9744,20 +9478,20 @@ not `js2-NAME', then we use the token info saved in 
instance vars."
 ;; Karl for coming up with the initial approach, which packs a lot of
 ;; punch for so little code.
 
-(defconst js-possibly-braceless-keywords-re
+(defconst js2-possibly-braceless-keywords-re
   (concat "else[ \t]+if\\|for[ \t]+each\\|"
           (regexp-opt '("catch" "do" "else" "finally" "for" "if"
                         "try" "while" "with" "let")))
   "Regular expression matching keywords that are optionally
 followed by an opening brace.")
 
-(defconst js-indent-operator-re
+(defconst js2-indent-operator-re
   (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
           (regexp-opt '("in" "instanceof") 'words))
   "Regular expression matching operators that affect indentation
 of continued expressions.")
 
-(defconst js-declaration-keyword-re
+(defconst js2-declaration-keyword-re
   (regexp-opt '("var" "let" "const") 'words)
   "Regular expression matching variable declaration keywords.")
 
@@ -9769,8 +9503,9 @@ of continued expressions.")
   nil)
 
 (defun js2-insert-and-indent (key)
-  "Run command bound to key and indent current line. Runs the command
-bound to KEY in the global keymap and indents the current line."
+  "Run command bound to KEY and indent current line.
+Runs the command bound to KEY in the global keymap and indents
+the current line."
   (interactive (list (this-command-keys)))
   (let ((cmd (lookup-key (current-global-map) key)))
     (if (commandp cmd)
@@ -9783,8 +9518,8 @@ bound to KEY in the global keymap and indents the current 
line."
                 (nth 4 parse-state))
       (indent-according-to-mode))))
 
-(defun js-re-search-forward-inner (regexp &optional bound count)
-  "Auxiliary function for `js-re-search-forward'."
+(defun js2-re-search-forward-inner (regexp &optional bound count)
+  "Auxiliary function for `js2-re-search-forward'."
   (let (parse saved-point)
     (while (> count 0)
       (re-search-forward regexp bound)
@@ -9805,18 +9540,18 @@ bound to KEY in the global keymap and indents the 
current line."
       (setq saved-point (point))))
   (point))
 
-(defun js-re-search-forward (regexp &optional bound noerror count)
-  "Search forward but ignore strings and comments. Invokes
-`re-search-forward' but treats the buffer as if strings and
-comments have been removed."
+(defun js2-re-search-forward (regexp &optional bound noerror count)
+  "Search forward but ignore strings and comments.
+Invokes `re-search-forward' but treats the buffer as if strings
+and comments have been removed."
   (let ((saved-point (point))
         (search-expr
          (cond ((null count)
-                '(js-re-search-forward-inner regexp bound 1))
+                '(js2-re-search-forward-inner regexp bound 1))
                ((< count 0)
-                '(js-re-search-backward-inner regexp bound (- count)))
+                '(js2-re-search-backward-inner regexp bound (- count)))
                ((> count 0)
-                '(js-re-search-forward-inner regexp bound count)))))
+                '(js2-re-search-forward-inner regexp bound count)))))
     (condition-case err
         (eval search-expr)
       (search-failed
@@ -9824,18 +9559,16 @@ comments have been removed."
        (unless noerror
          (error (error-message-string err)))))))
 
-(defun js-re-search-backward-inner (regexp &optional bound count)
-  "Auxiliary function for `js-re-search-backward'."
-  (let (parse saved-point)
+(defun js2-re-search-backward-inner (regexp &optional bound count)
+  "Auxiliary function for `js2-re-search-backward'."
+  (let (parse)
     (while (> count 0)
       (re-search-backward regexp bound)
-      (setq parse (if saved-point
-                      (parse-partial-sexp saved-point (point))
-                    (syntax-ppss (point))))
+      (setq parse (syntax-ppss (point)))
       (cond ((nth 3 parse)
              (re-search-backward
               (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
-              (save-excursion (beginning-of-line) (point)) t))
+              (line-beginning-position) t))
             ((nth 7 parse)
              (goto-char (nth 8 parse)))
             ((or (nth 4 parse)
@@ -9845,18 +9578,18 @@ comments have been removed."
              (setq count (1- count))))))
   (point))
 
-(defun js-re-search-backward (regexp &optional bound noerror count)
-  "Search backward but ignore strings and comments. Invokes
-`re-search-backward' but treats the buffer as if strings and
-comments have been removed."
+(defun js2-re-search-backward (regexp &optional bound noerror count)
+  "Search backward but ignore strings and comments.
+Invokes `re-search-backward' but treats the buffer as if strings
+and comments have been removed."
   (let ((saved-point (point))
         (search-expr
          (cond ((null count)
-                '(js-re-search-backward-inner regexp bound 1))
+                '(js2-re-search-backward-inner regexp bound 1))
                ((< count 0)
-                '(js-re-search-forward-inner regexp bound (- count)))
+                '(js2-re-search-forward-inner regexp bound (- count)))
                ((> count 0)
-                '(js-re-search-backward-inner regexp bound count)))))
+                '(js2-re-search-backward-inner regexp bound count)))))
     (condition-case err
         (eval search-expr)
       (search-failed
@@ -9864,57 +9597,50 @@ comments have been removed."
        (unless noerror
          (error (error-message-string err)))))))
 
-(defun js-looking-at-operator-p ()
-  "Return non-nil if text after point is an operator (that is not
-a comma)."
-  (save-match-data
-    (and (looking-at js-indent-operator-re)
-         (or (not (looking-at ":"))
-             (save-excursion
-               (and (js-re-search-backward "[?:{]\\|\\<case\\>" nil t)
-                    (looking-at "?")))))))
-
-(defun js-continued-expression-p ()
-  "Returns non-nil if the current line continues an expression."
+(defun js2-looking-at-operator-p ()
+  "Return non-nil if text after point is a non-comma operator."
+  (and (looking-at js2-indent-operator-re)
+       (or (not (looking-at ":"))
+           (save-excursion
+             (and (js2-re-search-backward "[?:{]\\|\\<case\\>" nil t)
+                  (looking-at "?"))))))
+
+(defun js2-continued-expression-p ()
+  "Return non-nil if the current line continues an expression."
   (save-excursion
     (back-to-indentation)
-    (or (js-looking-at-operator-p)
-        ;; comment
-        (and (js-re-search-backward "\n" nil t)
-            (progn
-              (skip-chars-backward " \t")
-               (unless (bolp)
-                 (backward-char)
-                 (and (js-looking-at-operator-p)
-                      (and (progn
-                             (backward-char)
-                             (not (looking-at 
"\\*\\|++\\|--\\|/[/*]")))))))))))
-
-(defun js-end-of-do-while-loop-p ()
-  "Returns non-nil if word after point is `while' of a do-while
+    (or (js2-looking-at-operator-p)
+        (when (js2-re-search-backward "\n" nil t)  ;; comment
+          (skip-chars-backward " \t")
+          (backward-char)
+          (when (js2-looking-at-operator-p)
+            (backward-char)
+            (not (looking-at "\\*\\|++\\|--\\|/[/*]")))))))
+
+(defun js2-end-of-do-while-loop-p ()
+  "Return non-nil if word after point is `while' of a do-while
 statement, else returns nil. A braceless do-while statement
 spanning several lines requires that the start of the loop is
 indented to the same column as the current line."
   (interactive)
   (save-excursion
-    (save-match-data
-      (when (looking-at "\\s-*\\<while\\>")
-       (if (save-excursion
-             (skip-chars-backward "[ \t\n]*}")
-             (looking-at "[ \t\n]*}"))
-           (save-excursion
-             (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
-         (js-re-search-backward "\\<do\\>" (point-at-bol) t)
-         (or (looking-at "\\<do\\>")
-             (let ((saved-indent (current-indentation)))
-               (while (and (js-re-search-backward "^[ \t]*\\<" nil t)
-                           (/= (current-indentation) saved-indent)))
-               (and (looking-at "[ \t]*\\<do\\>")
-                    (not (js-re-search-forward
-                          "\\<while\\>" (point-at-eol) t))
-                    (= (current-indentation) saved-indent)))))))))
-
-(defun js-multiline-decl-indentation ()
+    (when (looking-at "\\s-*\\<while\\>")
+      (if (save-excursion
+            (skip-chars-backward "[ \t\n]*}")
+            (looking-at "[ \t\n]*}"))
+          (save-excursion
+            (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
+        (js2-re-search-backward "\\<do\\>" (point-at-bol) t)
+        (or (looking-at "\\<do\\>")
+            (let ((saved-indent (current-indentation)))
+              (while (and (js2-re-search-backward "^[ \t]*\\<" nil t)
+                          (/= (current-indentation) saved-indent)))
+              (and (looking-at "[ \t]*\\<do\\>")
+                   (not (js2-re-search-forward
+                         "\\<while\\>" (point-at-eol) t))
+                   (= (current-indentation) saved-indent))))))))
+
+(defun js2-multiline-decl-indentation ()
   "Returns the declaration indentation column if the current line belongs
 to a multiline declaration statement.  All declarations are lined up 
vertically:
 
@@ -9931,12 +9657,12 @@ var o = {                               var bar = 2,
 },                                            foo: 3
     bar = 2;                                };
 "
-  (let (forward-sexp-function ; use lisp version
+  (let (forward-sexp-function ; use Lisp version
         at-opening-bracket)
     (save-excursion
       (back-to-indentation)
-      (when (not (looking-at js-declaration-keyword-re))
-        (when (looking-at js-indent-operator-re)
+      (when (not (looking-at js2-declaration-keyword-re))
+        (when (looking-at js2-indent-operator-re)
           (goto-char (match-end 0))) ; continued expressions are ok
         (while (and (not at-opening-bracket)
                     (not (bobp))
@@ -9947,26 +9673,26 @@ var o = {                               var bar = 2,
                             (and (not (eq (char-before) ?\;))
                                  (and
                                   (prog2 (skip-chars-backward "[[:punct:]]")
-                                      (looking-at js-indent-operator-re)
+                                      (looking-at js2-indent-operator-re)
                                     (js2-backward-sws))
                                   (not (eq (char-before) ?\;))))
                             (js2-same-line pos)))))
           (condition-case err
               (backward-sexp)
             (scan-error (setq at-opening-bracket t))))
-        (when (looking-at js-declaration-keyword-re)
+        (when (looking-at js2-declaration-keyword-re)
           (- (1+ (match-end 0)) (point-at-bol)))))))
 
-(defun js-ctrl-statement-indentation ()
-  "Returns the proper indentation of the current line if it
-starts the body of a control statement without braces, else
-returns nil."
-  (let (forward-sexp-function)  ; temporarily unbind it
+(defun js2-ctrl-statement-indentation ()
+  "Return the proper indentation of current line if it is a control statement.
+Returns an indentation if this line starts the body of a control
+statement without braces, else returns nil."
+  (let (forward-sexp-function)
     (save-excursion
       (back-to-indentation)
       (when (and (not (js2-same-line (point-min)))
                  (not (looking-at "{"))
-                 (js-re-search-backward "[[:graph:]]" nil t)
+                 (js2-re-search-backward "[[:graph:]]" nil t)
                  (not (looking-at "[{([]"))
                  (progn
                    (forward-char)
@@ -9976,9 +9702,9 @@ returns nil."
                      (skip-chars-backward " \t" (point-at-bol)))
                    (let ((pt (point)))
                      (back-to-indentation)
-                     (and (looking-at js-possibly-braceless-keywords-re)
+                     (and (looking-at js2-possibly-braceless-keywords-re)
                           (= (match-end 0) pt)
-                          (not (js-end-of-do-while-loop-p))))))
+                          (not (js2-end-of-do-while-loop-p))))))
         (+ (current-indentation) js2-basic-offset)))))
 
 (defun js2-indent-in-array-comp (parse-status)
@@ -9993,7 +9719,7 @@ In particular, return the buffer position of the first 
`for' kwd."
           (forward-char 1)
           (js2-forward-sws)
           (if (looking-at "[[{]")
-              (let (forward-sexp-function) ; use lisp version
+              (let (forward-sexp-function) ; use Lisp version
                 (forward-sexp)             ; skip destructuring form
                 (js2-forward-sws)
                 (if (and (/= (char-after) ?,) ; regular array
@@ -10019,15 +9745,15 @@ In particular, return the buffer position of the first 
`for' kwd."
       (goto-char for-kwd)
       (current-column))))
 
-(defun js-proper-indentation (parse-status)
+(defun js2-proper-indentation (parse-status)
   "Return the proper indentation for the current line."
   (save-excursion
     (back-to-indentation)
-    (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
+    (let ((ctrl-stmt-indent (js2-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
-          (continued-expr-p (js-continued-expression-p))
+          (continued-expr-p (js2-continued-expression-p))
           (declaration-indent (and js2-pretty-multiline-decl-indentation-p
-                                   (js-multiline-decl-indentation)))
+                                   (js2-multiline-decl-indentation)))
           (bracket (nth 1 parse-status))
           beg)
       (cond
@@ -10062,7 +9788,7 @@ In particular, return the buffer position of the first 
`for' kwd."
               (back-to-indentation)
               (when (and js2-pretty-multiline-decl-indentation-p
                          js2-always-indent-assigned-expr-in-decls-p
-                         (looking-at js-declaration-keyword-re))
+                         (looking-at js2-declaration-keyword-re))
                 (goto-char (1+ (match-end 0)))))
             (cond (same-indent-p
                    (current-column))
@@ -10102,7 +9828,7 @@ In particular, return the buffer position of the first 
`for' kwd."
   (interactive)
   (while (forward-comment 1)))
 
-(defsubst js2-current-indent (&optional pos)
+(defun js2-current-indent (&optional pos)
   "Return column of indentation on current line.
 If POS is non-nil, go to that point and return indentation for that line."
   (save-excursion
@@ -10111,15 +9837,14 @@ If POS is non-nil, go to that point and return 
indentation for that line."
     (back-to-indentation)
     (current-column)))
 
-(defsubst js2-arglist-close ()
+(defun js2-arglist-close ()
   "Return non-nil if we're on a line beginning with a close-paren/brace."
-  (save-match-data
-    (save-excursion
-      (goto-char (point-at-bol))
-      (js2-forward-sws)
-      (looking-at "[])}]"))))
+  (save-excursion
+    (goto-char (point-at-bol))
+    (js2-forward-sws)
+    (looking-at "[])}]")))
 
-(defsubst js2-indent-looks-like-label-p ()
+(defun js2-indent-looks-like-label-p ()
   (goto-char (point-at-bol))
   (js2-forward-sws)
   (looking-at (concat js2-mode-identifier-re ":")))
@@ -10136,11 +9861,11 @@ If POS is non-nil, go to that point and return 
indentation for that line."
      (save-excursion
        (js2-indent-looks-like-label-p)))))
 
-;; if prev line looks like foobar({ then we're passing an object
+;; If prev line looks like foobar({ then we're passing an object
 ;; literal to a function call, and people pretty much always want to
 ;; de-dent back to the previous line, so move the 'basic-offset'
 ;; position to the front.
-(defsubst js2-indent-objlit-arg-p (parse-status)
+(defun js2-indent-objlit-arg-p (parse-status)
   (save-excursion
     (back-to-indentation)
     (js2-backward-sws)
@@ -10151,16 +9876,15 @@ If POS is non-nil, go to that point and return 
indentation for that line."
            (skip-chars-backward " \t")
            (eq (char-before) ?\()))))
 
-(defsubst js2-indent-case-block-p ()
+(defun js2-indent-case-block-p ()
   (save-excursion
     (back-to-indentation)
     (js2-backward-sws)
     (goto-char (point-at-bol))
     (skip-chars-forward " \t")
-    (save-match-data
-      (looking-at "case\\s-.+:"))))
+    (looking-at "case\\s-.+:")))
 
-(defsubst js2-syntax-bol ()
+(defun js2-syntax-bol ()
   "Return the point at the first non-whitespace char on the line.
 Returns `point-at-bol' if the line is empty."
   (save-excursion
@@ -10168,7 +9892,7 @@ Returns `point-at-bol' if the line is empty."
     (skip-chars-forward " \t")
     (point)))
 
-(defun js2-bounce-indent (normal-col parse-status backwards)
+(defun js2-bounce-indent (normal-col parse-status &optional backwards)
   "Cycle among alternate computed indentation positions.
 PARSE-STATUS is the result of `parse-partial-sexp' from the beginning
 of the buffer to the current point.  NORMAL-COL is the indentation
@@ -10181,21 +9905,14 @@ in reverse."
         (current-line (save-excursion
                         (forward-line 0)  ; move to bol
                         (1+ (count-lines (point-min) (point)))))
-        positions
-        pos
-        main-pos
-        anchor
-        arglist-cont
-        same-indent
-        prev-line-col
-        basic-offset
-        computed-pos)
+        positions pos main-pos anchor arglist-cont same-indent
+        prev-line-col basic-offset computed-pos)
     ;; temporarily don't record undo info, if user requested this
-    (if js2-mode-indent-inhibit-undo
-        (setq buffer-undo-list t))
+    (when js2-mode-indent-inhibit-undo
+      (setq buffer-undo-list t))
     (unwind-protect
         (progn
-          ;; first likely point:  indent from beginning of previous code line
+          ;; First likely point:  indent from beginning of previous code line
           (push (setq basic-offset
                       (+ (save-excursion
                            (back-to-indentation)
@@ -10205,11 +9922,8 @@ in reverse."
                          js2-basic-offset))
                 positions)
 
-          ;; (first + epsilon) likely point:  indent 2x from beginning of
-          ;; previous code line.  Some companies like this approach.  Ahem.
-          ;; Seriously, though -- 4-space indent for expression continuation
-          ;; lines isn't a bad idea.  We should eventually implement it
-          ;; that way.
+          ;; (First + epsilon) likely point:  indent 2x from beginning of
+          ;; previous code line.  Google does it this way.
           (push (setq basic-offset
                       (+ (save-excursion
                            (back-to-indentation)
@@ -10219,23 +9933,22 @@ in reverse."
                          (* 2 js2-basic-offset)))
                 positions)
 
-          ;; second likely point:  indent from assign-expr RHS.  This
+          ;; Second likely point:  indent from assign-expr RHS.  This
           ;; is just a crude guess based on finding " = " on the previous
           ;; line containing actual code.
           (setq pos (save-excursion
-                      (save-match-data
-                        (forward-line -1)
-                        (goto-char (point-at-bol))
-                        (when (re-search-forward "\\s-+\\(=\\)\\s-+"
-                                                 (point-at-eol) t)
-                          (goto-char (match-end 1))
-                          (skip-chars-forward " \t\r\n")
-                          (current-column)))))
+                      (forward-line -1)
+                      (goto-char (point-at-bol))
+                      (when (re-search-forward "\\s-+\\(=\\)\\s-+"
+                                               (point-at-eol) t)
+                        (goto-char (match-end 1))
+                        (skip-chars-forward " \t\r\n")
+                        (current-column))))
           (when pos
             (incf pos js2-basic-offset)
             (push pos positions))
 
-          ;; third likely point:  same indent as previous line of code.
+          ;; Third likely point:  same indent as previous line of code.
           ;; Make it the first likely point if we're not on an
           ;; arglist-close line and previous line ends in a comma, or
           ;; both this line and prev line look like object-literal
@@ -10259,7 +9972,7 @@ in reverse."
                 (setq same-indent pos))
             (push pos positions))
 
-          ;; fourth likely point:  first preceding code with less indentation
+          ;; Fourth likely point:  first preceding code with less indentation.
           ;; than the immediately preceding code line.
           (setq pos (save-excursion
                       (back-to-indentation)
@@ -10340,30 +10053,26 @@ cycles between the computed indentation positions in 
reverse order."
   (interactive)
   (js2-indent-line t))
 
-(defsubst js2-1-line-comment-continuation-p ()
+(defun js2-1-line-comment-continuation-p ()
   "Return t if we're in a 1-line comment continuation.
 If so, we don't ever want to use bounce-indent."
   (save-excursion
-    (save-match-data
-      (and (progn
-             (forward-line 0)
-             (looking-at "\\s-*//"))
-           (progn
-             (forward-line -1)
-             (forward-line 0)
-             (when (looking-at "\\s-*$")
-               (js2-backward-sws)
-               (forward-line 0))
-             (looking-at "\\s-*//"))))))
+    (and (progn
+           (forward-line 0)
+           (looking-at "\\s-*//"))
+         (progn
+           (forward-line -1)
+           (forward-line 0)
+           (when (looking-at "\\s-*$")
+             (js2-backward-sws)
+             (forward-line 0))
+           (looking-at "\\s-*//")))))
 
 (defun js2-indent-line (&optional bounce-backwards)
   "Indent the current line as JavaScript source text."
   (interactive)
-  (let (parse-status
-        offset
-        indent-col
-        moved
-        ;; don't whine about errors/warnings when we're indenting.
+  (let (parse-status current-indent offset indent-col moved
+        ;; Don't whine about errors/warnings when we're indenting.
         ;; This has to be set before calling parse-partial-sexp below.
         (inhibit-point-motion-hooks t))
     (setq parse-status (save-excursion
@@ -10374,8 +10083,8 @@ If so, we don't ever want to use bounce-indent."
     (js2-with-underscore-as-word-syntax
      (if (nth 4 parse-status)
          (js2-lineup-comment parse-status)
-       (setq indent-col (js-proper-indentation parse-status))
-       ;; see comments below about js2-mode-last-indented-line
+       (setq indent-col (js2-proper-indentation parse-status))
+       ;; See comments below about `js2-mode-last-indented-line'.
        (cond
         ;; bounce-indenting is disabled during electric-key indent.
         ;; It doesn't work well on first line of buffer.
@@ -10397,38 +10106,89 @@ If so, we don't ever want to use bounce-indent."
     (indent-region start end nil) ; nil for byte-compiler
     (js2-mode-edit start end (- end start))))
 
-;;;###autoload (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+(defvar js2-minor-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-c C-`") #'js2-next-error)
+    (define-key map [mouse-1] #'js2-mode-show-node)
+    map)
+  "Keymap used when `js2-minor-mode' is active.")
+
+(define-minor-mode js2-minor-mode
+  "Minor mode for running js2 as a background linter.
+This allows you to use a different major mode for JavaScript editing,
+such as `espresso-mode', while retaining the asynchronous error/warning
+highlighting features of `js2-mode'."
+  :group 'js2-mode
+  :lighter " js-lint"
+  (if js2-minor-mode
+      (js2-minor-mode-enter)
+    (js2-minor-mode-exit)))
+
+(defun js2-minor-mode-enter ()
+  "Initialization for `js2-minor-mode'."
+  (set (make-local-variable 'max-lisp-eval-depth)
+       (max max-lisp-eval-depth 3000))
+  (setq next-error-function #'js2-next-error)
+  (setq js2-default-externs
+        (append js2-ecma-262-externs
+                (if js2-include-browser-externs js2-browser-externs)
+                (if js2-include-gears-externs js2-gears-externs)
+                (if js2-include-rhino-externs js2-rhino-externs)))
+  ;; Experiment:  make reparse-delay longer for longer files.
+  (if (plusp js2-dynamic-idle-timer-adjust)
+      (setq js2-idle-timer-delay
+            (* js2-idle-timer-delay
+               (/ (point-max) js2-dynamic-idle-timer-adjust))))
+  (setq js2-mode-buffer-dirty-p t
+        js2-mode-parsing nil
+        js2-highlight-level 0)  ; no syntax highlighting
+  (add-hook 'after-change-functions #'js2-minor-mode-edit nil t)
+  (add-hook 'change-major-mode-hook #'js2-minor-mode-exit nil t)
+  (js2-reparse))
+
+(defun js2-minor-mode-exit ()
+  "Turn off `js2-minor-mode'."
+  (setq next-error-function nil)
+  (remove-hook 'after-change-functions #'js2-mode-edit t)
+  (remove-hook 'change-major-mode-hook #'js2-minor-mode-exit t)
+  (when js2-mode-node-overlay
+    (delete-overlay js2-mode-node-overlay)
+    (setq js2-mode-node-overlay nil))
+  (js2-remove-overlays)
+  (setq js2-mode-ast nil))
+
+(defun js2-display-error-list ()
+  "Display a navigable buffer listing parse errors/warnings."
+  (interactive)
+  (if (not (js2-have-errors-p))
+      (message "No errors")
+    (let ((srcbuf (current-buffer))
+          (errbuf (get-buffer-create "*js-lint*"))
+          (errs (js2-errors-and-warnings)))
+      (setq errs (sort errs (lambda (e1 e2)
+                              (funcall '< (second e1) (second e2)))))
+      (with-current-buffer errbuf
+        (let ((inhibit-read-only t))
+          (erase-buffer)
+          (dolist (err errs)
+            (insert (format "%s\n" err)))
+          (pop-to-buffer errbuf))))))
 
 ;;;###autoload
-(defun js2-mode ()
+(define-derived-mode js2-mode prog-mode "Javascript-IDE"
+  ;; FIXME: Should derive from js-mode.
   "Major mode for editing JavaScript code."
-  (interactive)
-  (kill-all-local-variables)
-  (set-syntax-table js2-mode-syntax-table)
-  (use-local-map js2-mode-map)
-  (make-local-variable 'comment-start)
-  (make-local-variable 'comment-end)
-  (make-local-variable 'comment-start-skip)
-  (setq major-mode 'js2-mode
-        mode-name "JavaScript-IDE"
-        comment-start "//"  ; used by comment-region; don't change it
+  (setq comment-start "//"  ; used by comment-region; don't change it
         comment-end "")
-  (setq local-abbrev-table js2-mode-abbrev-table)
   (set (make-local-variable 'max-lisp-eval-depth)
        (max max-lisp-eval-depth 3000))
   (set (make-local-variable 'indent-line-function) #'js2-indent-line)
   (set (make-local-variable 'indent-region-function) #'js2-indent-region)
-
-  ;; I tried an "improvement" to `c-fill-paragraph' that worked out badly
-  ;; on most platforms other than the one I originally wrote it on.
-  ;; So it's back to `c-fill-paragraph'.
   (set (make-local-variable 'fill-paragraph-function) #'c-fill-paragraph)
-
-  (add-hook 'before-save-hook #'js2-before-save nil t)
-  (set (make-local-variable 'next-error-function) #'js2-next-error)
+  (set (make-local-variable 'comment-line-break-function) #'js2-line-break)
   (set (make-local-variable 'beginning-of-defun-function) 
#'js2-beginning-of-defun)
   (set (make-local-variable 'end-of-defun-function) #'js2-end-of-defun)
-  ;; we un-confuse `parse-partial-sexp' by setting syntax-table properties
+  ;; We un-confuse `parse-partial-sexp' by setting syntax-table properties
   ;; for characters inside regexp literals.
   (set (make-local-variable 'parse-sexp-lookup-properties) t)
   ;; this is necessary to make `show-paren-function' work properly
@@ -10436,6 +10196,12 @@ If so, we don't ever want to use bounce-indent."
   ;; needed for M-x rgrep, among other things
   (put 'js2-mode 'find-tag-default-function #'js2-mode-find-tag)
 
+  (set (make-local-variable 'electric-indent-chars)
+       (append '("{" "}" "(" ")" "[" "]" ":" ";" "," "*")
+               electric-indent-chars))
+  (set (make-local-variable 'electric-layout-rules)
+       '((?\; . after) (?\{ . after) (?\} . before)))
+
   ;; some variables needed by cc-engine for paragraph-fill, etc.
   (setq c-comment-prefix-regexp js2-comment-prefix-regexp
         c-comment-start-regexp "/[*/]\\|\\s|"
@@ -10458,31 +10224,22 @@ If so, we don't ever want to use bounce-indent."
 
   (setq js2-default-externs
         (append js2-ecma-262-externs
-                (if js2-include-browser-externs
-                    js2-browser-externs)
-                (if js2-include-gears-externs
-                    js2-gears-externs)
-                (if js2-include-rhino-externs
-                     js2-rhino-externs)))
-
-  ;; We do our own syntax highlighting based on the parse tree.
-  ;; However, we want minor modes that add keywords to highlight properly
-  ;; (examples:  doxymacs, column-marker).
-  ;; To customize highlighted keywords, use `font-lock-add-keywords'.
+                (if js2-include-browser-externs js2-browser-externs)
+                (if js2-include-gears-externs js2-gears-externs)
+                (if js2-include-rhino-externs js2-rhino-externs)))
+
   (setq font-lock-defaults '(nil t))
-  
+
   ;; Experiment:  make reparse-delay longer for longer files.
-  (if (plusp js2-dynamic-idle-timer-adjust)
-      (setq js2-idle-timer-delay
-            (* js2-idle-timer-delay
-               (/ (point-max) js2-dynamic-idle-timer-adjust))))
+  (when (plusp js2-dynamic-idle-timer-adjust)
+    (setq js2-idle-timer-delay
+          (* js2-idle-timer-delay
+             (/ (point-max) js2-dynamic-idle-timer-adjust))))
 
   (add-hook 'change-major-mode-hook #'js2-mode-exit nil t)
   (add-hook 'after-change-functions #'js2-mode-edit nil t)
   (setq imenu-create-index-function #'js2-mode-create-imenu-index)
   (imenu-add-to-menubar (concat "IM-" mode-name))
-  (when js2-mirror-mode
-    (js2-enter-mirror-mode))
   (add-to-invisibility-spec '(js2-outline . t))
   (set (make-local-variable 'line-move-ignore-invisible) t)
   (set (make-local-variable 'forward-sexp-function) #'js2-mode-forward-sexp)
@@ -10508,20 +10265,10 @@ If so, we don't ever want to use bounce-indent."
   (remove-hook 'change-major-mode-hook #'js2-mode-exit t)
   (remove-from-invisibility-spec '(js2-outline . t))
   (js2-mode-show-all)
-  (js2-with-unmodifying-text-property-changes
+  (with-silent-modifications
     (js2-clear-face (point-min) (point-max))))
 
-(defun js2-before-save ()
-  "Clean up whitespace before saving file.
-You can disable this by customizing `js2-cleanup-whitespace'."
-  (when js2-cleanup-whitespace
-    (let ((col (current-column)))
-      (delete-trailing-whitespace)
-      ;; don't change trailing whitespace on current line
-      (unless (eq (current-column) col)
-        (indent-to col)))))
-
-(defsubst js2-mode-reset-timer ()
+(defun js2-mode-reset-timer ()
   "Cancel any existing parse timer and schedule a new one."
   (if js2-mode-parse-timer
       (cancel-timer js2-mode-parse-timer))
@@ -10549,16 +10296,15 @@ it to be reparsed when the buffer is selected."
 
 (defun js2-mode-edit (beg end len)
   "Schedule a new parse after buffer is edited.
-Buffer edit spans from BEG to END and is of length LEN.
-Also clears the `js2-magic' bit on autoinserted parens/brackets
-if the edit occurred on a line different from the magic paren."
-  (let* ((magic-pos (next-single-property-change (point-min) 'js2-magic))
-         (line (if magic-pos (line-number-at-pos magic-pos))))
-    (and line
-         (or (/= (line-number-at-pos beg) line)
-             (and (> 0 len)
-                  (/= (line-number-at-pos end) line)))
-         (js2-mode-mundanify-parens)))
+Buffer edit spans from BEG to END and is of length LEN."
+  (setq js2-mode-buffer-dirty-p t)
+  (js2-mode-hide-overlay)
+  (js2-mode-reset-timer))
+
+(defun js2-minor-mode-edit (beg end len)
+  "Callback for buffer edits in `js2-mode'.
+Schedules a new parse after buffer is edited.
+Buffer edit spans from BEG to END and is of length LEN."
   (setq js2-mode-buffer-dirty-p t)
   (js2-mode-hide-overlay)
   (js2-mode-reset-timer))
@@ -10576,7 +10322,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
       (unwind-protect
           (when (or js2-mode-buffer-dirty-p force)
             (js2-remove-overlays)
-            (js2-with-unmodifying-text-property-changes
+            (with-silent-modifications
               (setq js2-mode-buffer-dirty-p nil
                     js2-mode-fontifications nil
                     js2-mode-deferred-properties nil)
@@ -10595,7 +10341,6 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                              (js2-mode-remove-suppressed-warnings)
                              (js2-mode-show-warnings)
                              (js2-mode-show-errors)
-                             (js2-mode-highlight-magic-parens)
                              (if (>= js2-highlight-level 1)
                                  (js2-highlight-jsdoc js2-mode-ast))
                              nil))))
@@ -10614,8 +10359,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
   "Debugging aid:  highlight selected AST node on mouse click."
   (interactive)
   (let ((node (js2-node-at-point))
-        beg
-        end)
+        beg end)
     (when js2-mode-show-overlay
       (if (null node)
           (message "No node found at location %s" (point))
@@ -10625,7 +10369,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
             (move-overlay js2-mode-node-overlay beg end)
           (setq js2-mode-node-overlay (make-overlay beg end))
           (overlay-put js2-mode-node-overlay 'font-lock-face 'highlight))
-        (js2-with-unmodifying-text-property-changes
+        (with-silent-modifications
           (put-text-property beg end 'point-left #'js2-mode-hide-overlay))
         (message "%s, parent: %s"
                  (js2-node-short-name node)
@@ -10643,7 +10387,7 @@ P1 and P2 are the old and new values of point, 
respectively."
       (unless (and p2
                    (>= p2 beg)
                    (<= p2 end))
-        (js2-with-unmodifying-text-property-changes
+        (with-silent-modifications
           (remove-text-properties beg end '(point-left nil)))
         (delete-overlay js2-mode-node-overlay)
         (setq js2-mode-node-overlay nil)))))
@@ -10654,7 +10398,7 @@ P1 and P2 are the old and new values of point, 
respectively."
   (js2-mode-exit)
   (js2-mode))
 
-(defsubst js2-mode-show-warn-or-err (e face)
+(defun js2-mode-show-warn-or-err (e face)
   "Highlight a warning or error E with FACE.
 E is a list of ((MSG-KEY MSG-ARG) BEG END)."
   (let* ((key (first e))
@@ -10749,26 +10493,18 @@ This ensures that the counts and `next-error' are 
correct."
 
 (defalias #'js2-echo-help #'js2-echo-error)
 
-(defun js2-enter-key ()
-  "Handle user pressing the Enter key."
-  (interactive)
-  (let ((parse-status (save-excursion
-                        (syntax-ppss (point))))
-        (js2-bounce-indent-p nil))
+(defun js2-line-break (&optional soft)
+  "Break line at point."
+  (let ((parse-status (syntax-ppss)))
     (cond
-     ;; check if we're inside a string
+     ;; Check if we're inside a string.
      ((nth 3 parse-status)
       (js2-mode-split-string parse-status))
-     ;; check if inside a block comment
+     ;; Check if inside a block comment.
      ((nth 4 parse-status)
       (js2-mode-extend-comment))
      (t
-      ;; should probably figure out what the mode-map says we should do
-      (if js2-indent-on-enter-key
-          (js2-indent-line))
-      (insert "\n")
-      (if js2-enter-indents-newline
-          (js2-indent-line))))))
+      (newline)))))
 
 (defun js2-mode-split-string (parse-status)
   "Turn a newline in mid-string into a string concatenation.
@@ -10777,17 +10513,16 @@ PARSE-STATUS is as documented in 
`parse-partial-sexp'."
          (quote-char (nth 3 parse-status))
          (quote-string (string quote-char))
          (string-beg (nth 8 parse-status))
-         (indent (save-match-data
-                   (or
-                    (save-excursion
-                      (back-to-indentation)
-                      (if (looking-at "\\+")
-                          (current-column)))
-                    (save-excursion
-                      (goto-char string-beg)
-                      (if (looking-back "\\+\\s-+")
-                          (goto-char (match-beginning 0)))
-                      (current-column))))))
+         (indent (or
+                  (save-excursion
+                    (back-to-indentation)
+                    (if (looking-at "\\+")
+                        (current-column)))
+                  (save-excursion
+                    (goto-char string-beg)
+                    (if (looking-back "\\+\\s-+")
+                        (goto-char (match-beginning 0)))
+                    (current-column)))))
     (insert quote-char "\n")
     (indent-to indent)
     (insert "+ " quote-string)
@@ -10875,33 +10610,12 @@ Also moves past comment delimiters when inside 
comments."
       (skip-chars-backward " \t")
     (goto-char (point-at-eol))))
 
-(defun js2-enter-mirror-mode()
-  "Turns on mirror mode, where quotes, brackets etc are mirrored automatically
-  on insertion."
-  (interactive)
-  (define-key js2-mode-map (read-kbd-macro "{")  'js2-mode-match-curly)
-  (define-key js2-mode-map (read-kbd-macro "}")  'js2-mode-magic-close-paren)
-  (define-key js2-mode-map (read-kbd-macro "\"") 'js2-mode-match-double-quote)
-  (define-key js2-mode-map (read-kbd-macro "'")  'js2-mode-match-single-quote)
-  (define-key js2-mode-map (read-kbd-macro "(")  'js2-mode-match-paren)
-  (define-key js2-mode-map (read-kbd-macro ")")  'js2-mode-magic-close-paren)
-  (define-key js2-mode-map (read-kbd-macro "[")  'js2-mode-match-bracket)
-  (define-key js2-mode-map (read-kbd-macro "]")  'js2-mode-magic-close-paren))
-
-(defun js2-leave-mirror-mode()
-  "Turns off mirror mode."
-  (interactive)
-  (dolist (key '("{" "\"" "'" "(" ")" "[" "]"))
-    (define-key js2-mode-map (read-kbd-macro key) 'self-insert-command)))
-
 (defsubst js2-mode-inside-string ()
   "Return non-nil if inside a string.
 Actually returns the quote character that begins the string."
-   (let ((parse-state (save-excursion
-                        (syntax-ppss (point)))))
-      (nth 3 parse-state)))
+  (nth 3 (syntax-ppss)))
 
-(defsubst js2-mode-inside-comment-or-string ()
+(defun js2-mode-inside-comment-or-string ()
   "Return non-nil if inside a comment or string."
   (or
    (let ((comment-start
@@ -10911,83 +10625,10 @@ Actually returns the quote character that begins the 
string."
                 (match-beginning 0)))))
      (and comment-start
           (<= comment-start (point))))
-   (let ((parse-state (save-excursion
-                        (syntax-ppss (point)))))
+   (let ((parse-state (syntax-ppss)))
      (or (nth 3 parse-state)
          (nth 4 parse-state)))))
 
-(defsubst js2-make-magic-delimiter (delim &optional pos)
-  "Add `js2-magic' and `js2-magic-paren-face' to DELIM, a string.
-Sets value of `js2-magic' text property to line number at POS."
-  (propertize delim
-              'js2-magic (line-number-at-pos pos)
-              'font-lock-face 'js2-magic-paren-face))
-
-(defun js2-mode-match-delimiter (open close)
-  "Insert OPEN (a string) and possibly matching delimiter CLOSE.
-The rule we use, which as far as we can tell is how Eclipse works,
-is that we insert the match if we're not in a comment or string,
-and the next non-whitespace character is either punctuation or
-occurs on another line."
-  (insert open)
-  (when (and (looking-at "\\s-*\\([[:punct:]]\\|$\\)")
-             (not (js2-mode-inside-comment-or-string)))
-    (save-excursion
-      (insert (js2-make-magic-delimiter close)))
-    (when js2-auto-indent-p
-      (let ((js2-bounce-indent-p (js2-code-at-bol-p)))
-        (js2-indent-line)))))
-
-(defun js2-mode-match-bracket ()
-  "Insert matching bracket."
-  (interactive)
-  (js2-mode-match-delimiter "[" "]"))
-
-(defun js2-mode-match-paren ()
-  "Insert matching paren unless already inserted."
-  (interactive)
-  (js2-mode-match-delimiter "(" ")"))
-
-(defun js2-mode-match-curly (arg)
-  "Insert matching curly-brace.
-With prefix arg, no formatting or indentation will occur -- the close-brace
-is simply inserted directly at the point."
-  (interactive "p")
-  (let (try-pos)
-    (cond
-     (current-prefix-arg
-      (js2-mode-match-delimiter "{" "}"))
-     ((and js2-auto-insert-catch-block
-           (setq try-pos (if (looking-back "\\s-*\\(try\\)\\s-*"
-                                           (point-at-bol))
-                             (match-beginning 1))))
-      (js2-insert-catch-skel try-pos))
-     (t
-      ;; Otherwise try to do something smarter.
-      (insert "{")
-      (unless (or (not (looking-at "\\s-*$"))
-                  (save-excursion
-                    (skip-chars-forward " \t\r\n")
-                    (and (looking-at "}")
-                         (js2-error-at-point)))
-                  (js2-mode-inside-comment-or-string))
-        (undo-boundary)
-        ;; absolutely mystifying bug:  when inserting the next "\n",
-        ;; the buffer-undo-list is given two new entries:  the inserted range,
-        ;; and the incorrect position of the point.  It's recorded incorrectly
-        ;; as being before the opening "{", not after it.  But it's recorded
-        ;; as the correct value if you're debugging `js2-mode-match-curly'
-        ;; in edebug.  I have no idea why it's doing this, but incrementing
-        ;; the inserted position fixes the problem, so that the undo takes us
-        ;; back to just after the user-inserted "{".
-        (insert "\n")
-        (ignore-errors
-          (incf (cadr buffer-undo-list)))
-        (js2-indent-line)
-        (save-excursion
-          (insert "\n}")
-          (let ((js2-bounce-indent-p (js2-code-at-bol-p)))
-            (js2-indent-line))))))))
 
 (defun js2-insert-catch-skel (try-pos)
   "Complete a try/catch block after inserting a { following a try keyword.
@@ -11010,98 +10651,6 @@ already have been inserted."
       (indent-to try-col)
       (insert "}"))))
 
-(defun js2-mode-highlight-magic-parens ()
-  "Re-highlight magic parens after parsing nukes the 'face prop."
-  (let ((beg (point-min))
-        end)
-    (while (setq beg (next-single-property-change beg 'js2-magic))
-      (setq end (next-single-property-change (1+ beg) 'js2-magic))
-      (if (get-text-property beg 'js2-magic)
-          (js2-with-unmodifying-text-property-changes
-            (put-text-property beg (or end (1+ beg))
-                               'font-lock-face 'js2-magic-paren-face))))))
-
-(defun js2-mode-mundanify-parens ()
-  "Clear all magic parens and brackets."
-  (let ((beg (point-min))
-        end)
-    (while (setq beg (next-single-property-change beg 'js2-magic))
-      (setq end (next-single-property-change (1+ beg) 'js2-magic))
-      (remove-text-properties beg (or end (1+ beg))
-                              '(js2-magic face)))))
-
-(defsubst js2-match-quote (quote-string)
-  (let ((start-quote (js2-mode-inside-string)))
-    (cond
-     ;; inside a comment - don't do quote-matching, since we can't
-     ;; reliably figure out if we're in a string inside the comment
-     ((js2-comment-at-point)
-      (insert quote-string))
-     ((not start-quote)
-      ;; not in string => insert matched quotes
-      (insert quote-string)
-      ;; exception:  if we're just before a word, don't double it.
-      (unless (looking-at "[^ \t\r\n]")
-        (save-excursion
-          (insert quote-string))))
-     ((looking-at quote-string)
-      (if (looking-back "[^\\]\\\\")
-          (insert quote-string)
-        (forward-char 1)))
-     ((and js2-mode-escape-quotes
-           (save-excursion
-             (save-match-data
-               (re-search-forward quote-string (point-at-eol) t))))
-      ;; inside terminated string, escape quote (unless already escaped)
-      (insert (if (looking-back "[^\\]\\\\")
-                  quote-string
-                (concat "\\" quote-string))))
-     (t
-      (insert quote-string)))))        ; else terminate the string
-
-(defun js2-mode-match-single-quote ()
-  "Insert matching single-quote."
-  (interactive)
-  (let ((parse-status (syntax-ppss (point))))
-    ;; don't match inside comments, since apostrophe is more common
-    (if (nth 4 parse-status)
-        (insert "'")
-      (js2-match-quote "'"))))
-
-(defun js2-mode-match-double-quote ()
-  "Insert matching double-quote."
-  (interactive)
-  (js2-match-quote "\""))
-
-;; Eclipse works as follows:
-;;  * type an open-paren and it auto-inserts close-paren
-;;    - auto-inserted paren gets a green bracket
-;;    - green bracket means typing close-paren there will skip it
-;;  * if you insert any text on a different line, it turns off
-(defun js2-mode-magic-close-paren ()
-  "Skip over close-paren rather than inserting, where appropriate."
-  (interactive)
-  (let* ((here (point))
-         (parse-status (syntax-ppss here))
-         (open-pos (nth 1 parse-status))
-         (close last-input-event)
-         (open (cond
-                ((eq close ?\))
-                 ?\()
-                ((eq close ?\])
-                 ?\[)
-                ((eq close ?})
-                 ?{)
-                (t nil))))
-    (if (and (eq (char-after) close)
-             (eq open (char-after open-pos))
-             (js2-same-line open-pos)
-             (get-text-property here 'js2-magic))
-        (progn
-          (remove-text-properties here (1+ here) '(js2-magic face))
-          (forward-char 1))
-      (insert-char close 1))
-    (blink-matching-open)))
 
 (defun js2-mode-wait-for-parse (callback)
   "Invoke CALLBACK when parsing is finished.
@@ -11169,31 +10718,30 @@ Returns nil if point is not in a function."
   (interactive)
   (let (comment fn pos)
     (save-excursion
-      (save-match-data
-        (cond
-         ;; /* ... */ comment?
-         ((js2-block-comment-p (setq comment (js2-comment-at-point)))
-          (if (js2-mode-invisible-overlay-bounds
-               (setq pos (+ 3 (js2-node-abs-pos comment))))
-              (progn
-                (goto-char pos)
-                (js2-mode-show-element))
-            (js2-mode-hide-element)))
-         ;; //-comment?
-         ((save-excursion
-            (back-to-indentation)
-            (looking-at js2-mode-//-comment-re))
-          (js2-mode-toggle-//-comment))
-         ;; function?
-         ((setq fn (js2-mode-function-at-point))
-          (setq pos (and (js2-function-node-body fn)
-                         (js2-node-abs-pos (js2-function-node-body fn))))
-          (goto-char (1+ pos))
-          (if (js2-mode-invisible-overlay-bounds)
-              (js2-mode-show-element)
-            (js2-mode-hide-element)))
-         (t
-          (message "Nothing at point to hide or show")))))))
+      (cond
+       ;; /* ... */ comment?
+       ((js2-block-comment-p (setq comment (js2-comment-at-point)))
+        (if (js2-mode-invisible-overlay-bounds
+             (setq pos (+ 3 (js2-node-abs-pos comment))))
+            (progn
+              (goto-char pos)
+              (js2-mode-show-element))
+          (js2-mode-hide-element)))
+       ;; //-comment?
+       ((save-excursion
+          (back-to-indentation)
+          (looking-at js2-mode-//-comment-re))
+        (js2-mode-toggle-//-comment))
+       ;; function?
+       ((setq fn (js2-mode-function-at-point))
+        (setq pos (and (js2-function-node-body fn)
+                       (js2-node-abs-pos (js2-function-node-body fn))))
+        (goto-char (1+ pos))
+        (if (js2-mode-invisible-overlay-bounds)
+            (js2-mode-show-element)
+          (js2-mode-hide-element)))
+       (t
+        (message "Nothing at point to hide or show"))))))
 
 (defun js2-mode-hide-element ()
   "Fold/hide contents of a block, showing ellipses.
@@ -11310,7 +10858,7 @@ to open an individual entry."
           (js2-mode-hide-comment n))))
     (js2-mode-hide-//-comments)))
 
-(defsubst js2-mode-extend-//-comment (direction)
+(defun js2-mode-extend-//-comment (direction)
   "Find start or end of a block of similar //-comment lines.
 DIRECTION is -1 to look back, 1 to look forward.
 INDENT is the indentation level to match.
@@ -11320,27 +10868,25 @@ If there is no such matching line, returns current 
end of line."
   (let ((pos (point-at-eol))
         (indent (current-indentation)))
     (save-excursion
-      (save-match-data
-        (while (and (zerop (forward-line direction))
-                    (looking-at js2-mode-//-comment-re)
-                    (eq indent (length (match-string 1))))
-          (setq pos (point-at-eol)))
+      (while (and (zerop (forward-line direction))
+                  (looking-at js2-mode-//-comment-re)
+                  (eq indent (length (match-string 1))))
+        (setq pos (point-at-eol))
       pos))))
 
 (defun js2-mode-hide-//-comments ()
   "Fold adjacent 1-line comments, showing only snippet of first one."
   (let (beg end)
     (save-excursion
-      (save-match-data
-        (goto-char (point-min))
-        (while (re-search-forward js2-mode-//-comment-re nil t)
-          (setq beg (point)
-                end (js2-mode-extend-//-comment 1))
-          (unless (eq beg end)
-            (overlay-put (js2-mode-flag-region beg end 'hide)
-                         'comment t))
-          (goto-char end)
-          (forward-char 1))))))
+      (goto-char (point-min))
+      (while (re-search-forward js2-mode-//-comment-re nil t)
+        (setq beg (point)
+              end (js2-mode-extend-//-comment 1))
+        (unless (eq beg end)
+          (overlay-put (js2-mode-flag-region beg end 'hide)
+                       'comment t))
+        (goto-char end)
+        (forward-char 1)))))
 
 (defun js2-mode-toggle-//-comment ()
   "Fold or un-fold any multi-line //-comment at point.
@@ -11390,7 +10936,7 @@ Some users don't like having warnings/errors reported 
while they type."
   (interactive)
   (setq js2-mode-show-parse-errors (not js2-mode-show-parse-errors)
         js2-mode-show-strict-warnings (not js2-mode-show-strict-warnings))
-  (if (interactive-p)
+  (if (called-interactively-p 'any)
       (message "warnings and errors %s"
                (if js2-mode-show-parse-errors
                    "enabled"
@@ -11407,8 +10953,6 @@ With ARG, do it that many times.  Negative arg -N means
 move backward across N balanced expressions."
   (interactive "p")
   (setq arg (or arg 1))
-  (if js2-mode-buffer-dirty-p
-      (js2-mode-wait-for-parse #'js2-mode-forward-sexp))
   (let (node end (start (point)))
     (cond
      ;; backward-sexp
@@ -11434,21 +10978,37 @@ move backward across N balanced expressions."
                              (js2-node-len node))))
        (goto-char (or end (point-max))))))))
 
+(defun js2-errors ()
+  "Return a list of errors found."
+  (and js2-mode-ast
+       (js2-ast-root-errors js2-mode-ast)))
+
+(defun js2-warnings ()
+  "Return a list of warnings found."
+  (and js2-mode-ast
+       (js2-ast-root-warnings js2-mode-ast)))
+
+(defun js2-have-errors-p ()
+  "Return non-nil if any parse errors or warnings were found."
+  (or (js2-errors) (js2-warnings)))
+
+(defun js2-errors-and-warnings ()
+  "Return a copy of the concatenated errors and warnings lists."
+  (and js2-mode-ast
+       (append (js2-ast-root-errors js2-mode-ast)
+               (copy-sequence (js2-ast-root-warnings js2-mode-ast)))))
+
 (defun js2-next-error (&optional arg reset)
   "Move to next parse error.
 Typically invoked via \\[next-error].
 ARG is the number of errors, forward or backward, to move.
 RESET means start over from the beginning."
   (interactive "p")
-  (if (or (null js2-mode-ast)
-          (and (null (js2-ast-root-errors js2-mode-ast))
-               (null (js2-ast-root-warnings js2-mode-ast))))
+  (if (not (or (js2-errors) (js2-warnings)))
       (message "No errors")
     (when reset
       (goto-char (point-min)))
-    (let* ((errs (copy-sequence
-                  (append (js2-ast-root-errors js2-mode-ast)
-                          (js2-ast-root-warnings js2-mode-ast))))
+    (let* ((errs (js2-errors-and-warnings))
            (continue t)
            (start (point))
            (count (or arg 1))
@@ -11456,13 +11016,12 @@ RESET means start over from the beginning."
            (sorter (if backward '> '<))
            (stopper (if backward '< '>))
            (count (abs count))
-           all-errs
-           err)
-      ;; sort by start position
+           all-errs err)
+      ;; Sort by start position.
       (setq errs (sort errs (lambda (e1 e2)
                               (funcall sorter (second e1) (second e2))))
             all-errs errs)
-      ;; find nth error with pos > start
+      ;; Find nth error with pos > start.
       (while (and errs continue)
         (when (funcall stopper (cadar errs) start)
           (setq err (car errs))
@@ -11471,9 +11030,9 @@ RESET means start over from the beginning."
         (setq errs (cdr errs)))
       (if err
           (goto-char (second err))
-        ;; wrap around to first error
+        ;; Wrap around to first error.
         (goto-char (second (car all-errs)))
-        ;; if we were already on it, echo msg again
+        ;; If we were already on it, echo msg again.
         (if (= (point) start)
             (js2-echo-error (point) (point)))))))
 
@@ -11565,9 +11124,9 @@ or script-level element."
                      (js2-node-parent-script-or-fn node)))
          script)
     (unless (js2-function-node-p parent)
-      ;; use current script-level node, or, if none, the next one
-      (setq script (or parent node))
-      (setq parent (js2-node-find-child-before (point) script))
+      ;; Use current script-level node, or, if none, the next one.
+      (setq script (or parent node)
+            parent (js2-node-find-child-before (point) script))
       (when (or (null parent)
                 (>= (point) (+ (js2-node-abs-pos parent)
                                (js2-node-len parent))))

commit c47c034230639afd5abf8ba22e696be9aeaf0387
Merge: ba301c3 cd7950c
Author: Dmitry Gutov <address@hidden>
Date:   Thu Apr 19 07:24:00 2012 +0400

    Merge remote-tracking branch 'origin/master'

diff --cc js2-mode.el
index 98b0fe4,77074d7..73c9608
--- a/js2-mode.el
+++ b/js2-mode.el
@@@ -11536,29 -11533,45 +11536,45 @@@ Parent is defined as the enclosing scri
      (when (setq sib (js2-node-find-child-before (point) parent))
        (goto-char (js2-node-abs-pos sib)))))
  
- (defun js2-beginning-of-defun ()
-   "Go to line on which current function starts, and return non-nil.
- If we're not in a function, go to beginning of previous script-level element."
-   (interactive)
-   (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point)))
-         pos sib)
-     (cond
-      ((and (js2-function-node-p parent)
-            (not (eq (point) (setq pos (js2-node-abs-pos parent)))))
-       (goto-char pos))
-      (t
-       (js2-mode-backward-sibling)))))
+ (defun js2-beginning-of-defun (&optional arg)
+   "Go to line on which current function starts, and return t on success.
+ If we're not in a function or already at the beginning of one, go
+ to beginning of previous script-level element.
 -With ARG N, do that N times. If N is negative, move "
++With ARG N, do that N times. If N is negative, move forward."
+   (setq arg (or arg 1))
+   (if (plusp arg)
+       (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point))))
+         (when (cond
+                ((js2-function-node-p parent)
+                 (goto-char (js2-node-abs-pos parent)))
+                (t
+                 (js2-mode-backward-sibling)))
+           (if (> arg 1)
+               (js2-beginning-of-defun (1- arg))
+             t)))
+     (when (js2-end-of-defun)
+       (if (>= arg -1)
+           (js2-beginning-of-defun 1)
+         (js2-beginning-of-defun (1+ arg))))))
  
  (defun js2-end-of-defun ()
-   "Go to the char after the last position of the current function.
- If we're not in a function, skips over the next script-level element."
-   (interactive)
-   (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point))))
-     (if (not (js2-function-node-p parent))
-         ;; punt:  skip over next script-level element beyond point
-         (js2-mode-forward-sibling)
-       (goto-char (+ 1 (+ (js2-node-abs-pos parent)
-                          (js2-node-len parent)))))))
+   "Go to the char after the last position of the current function
+ or script-level element."
+   (let* ((node (js2-node-at-point))
+          (parent (or (and (js2-function-node-p node) node)
+                      (js2-node-parent-script-or-fn node)))
+          script)
+     (unless (js2-function-node-p parent)
+       ;; use current script-level node, or, if none, the next one
+       (setq script (or parent node))
+       (setq parent (js2-node-find-child-before (point) script))
+       (when (or (null parent)
+                 (>= (point) (+ (js2-node-abs-pos parent)
+                                (js2-node-len parent))))
+         (setq parent (js2-node-find-child-after (point) script))))
+     (when parent
+       (goto-char (+ (js2-node-abs-pos parent)
+                     (js2-node-len parent))))))
  
  (defun js2-mark-defun (&optional allow-extend)
    "Put mark at end of this function, point at beginning.

commit ba301c31868bcf8ac0ce43feb0e83944cd91971f
Author: Dmitry Gutov <address@hidden>
Date:   Thu Apr 19 07:15:33 2012 +0400

    Only change window-configuration-change-hook's local value

diff --git a/js2-mode.el b/js2-mode.el
index 30c7bbe..98b0fe4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10539,7 +10539,7 @@ it to be reparsed when the buffer is selected."
     (with-current-buffer buffer
       (add-hook 'window-configuration-change-hook
                 #'js2-mode-idle-reparse-inner
-                t))))
+                nil t))))
 
 (defun js2-mode-idle-reparse-inner ()
   (remove-hook 'window-configuration-change-hook

commit 93480bf9fe6cd4ab2983854b448dafc1a1034eb3
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 16 05:13:37 2012 +0400

    Guess more carefully when indenting array comprehension
    
    Fixes #42

diff --git a/js2-mode.el b/js2-mode.el
index eaef485..30c7bbe 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9984,10 +9984,11 @@ returns nil."
 (defun js2-indent-in-array-comp (parse-status)
   "Return non-nil if we think we're in an array comprehension.
 In particular, return the buffer position of the first `for' kwd."
-  (let ((end (point)))
-    (when (nth 1 parse-status)
+  (let ((bracket (nth 1 parse-status))
+        (end (point)))
+    (when bracket
       (save-excursion
-        (goto-char (nth 1 parse-status))
+        (goto-char bracket)
         (when (looking-at "\\[")
           (forward-char 1)
           (js2-forward-sws)
@@ -10001,7 +10002,9 @@ In particular, return the buffer position of the first 
`for' kwd."
             ;; to skip arbitrary expressions we need the parser,
             ;; so we'll just guess at it.
             (if (and (> end (point)) ; not empty literal
-                     (re-search-forward "[^,]]* \\(for\\) " end t))
+                     (re-search-forward "[^,]]* \\(for\\) " end t)
+                     ;; not inside a string literal
+                     (not (nth 3 (parse-partial-sexp bracket (point)))))
                 (match-beginning 1))))))))
 
 (defun js2-array-comp-indentation (parse-status for-kwd)

commit 0731bb3b41531a64ab2ce7c37c20471d231d3219
Author: Leo Liu <address@hidden>
Date:   Mon Apr 2 14:54:50 2012 +0800

    Add optional arg DIRECTORY to ack

diff --git a/ack.el b/ack.el
index dfd3fd2..61ce7a0 100644
--- a/ack.el
+++ b/ack.el
@@ -136,14 +136,19 @@ This gets tacked on the end of the generated 
expressions.")
   (add-hook 'compilation-filter-hook 'ack-filter nil t))
 
 ;;;###autoload
-(defun ack (command-args)
+(defun ack (command-args &optional directory)
   "Run ack using COMMAND-ARGS and collect output in a buffer.
+With prefix, ask for the DIRECTORY to run ack.
 
 \\{ack-mode-map}"
   (interactive
    (list (read-from-minibuffer "Run ack (like this): "
-                               ack-command nil nil 'ack-history)))
-  (compilation-start command-args 'ack-mode))
+                               ack-command nil nil 'ack-history)
+         (and current-prefix-arg
+              (read-directory-name "In directory: " nil nil t))))
+  (let ((default-directory (expand-file-name
+                            (or directory default-directory))))
+    (compilation-start command-args 'ack-mode)))
 
 (provide 'ack)
 ;;; ack.el ends here

commit 31f297213970e0edf2ec30442ef812ae02527a7b
Author: Leo Liu <address@hidden>
Date:   Mon Mar 26 19:07:10 2012 +0800

    Improve last change

diff --git a/ack.el b/ack.el
index 69fc523..dfd3fd2 100644
--- a/ack.el
+++ b/ack.el
@@ -106,7 +106,9 @@ This gets tacked on the end of the generated expressions.")
 (defun ack--file ()
   (let (file)
     (save-excursion
-      (forward-line -1)
+      (while (progn
+               (forward-line -1)
+               (looking-at-p "^--$")))
       (setq file (or (get-text-property (line-beginning-position) 'ack-file)
                      (buffer-substring-no-properties
                       (line-beginning-position) (line-end-position)))))
@@ -115,10 +117,12 @@ This gets tacked on the end of the generated 
expressions.")
     (list file)))
 
 (defconst ack-regexp-alist
-  '(("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\([1-9][0-9]*\\)\\2\\)?"
-     1 3 (ack--column-start . ack--column-end))
+  '(;; grouping line (--group or --heading)
     ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:[1-9][0-9]*\\2\\)?"
      ack--file 1 (ack--column-start . ack--column-end))
+    ;; none grouping line (--nogroup or --noheading)
+    ("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\([1-9][0-9]*\\)\\2\\)?"
+     1 3 (ack--column-start . ack--column-end))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit 3c84dbd55d38c1a2aa53db354047ec73b9ede3d0
Author: Leo Liu <address@hidden>
Date:   Mon Mar 26 00:14:25 2012 +0800

    Remove requirement for --nogroup or --noheading switch
    
    and some minor tweaks.

diff --git a/ack.el b/ack.el
index 8a3ec2c..69fc523 100644
--- a/ack.el
+++ b/ack.el
@@ -41,12 +41,9 @@
   :type 'boolean
   :group 'ack)
 
-(defcustom ack-command "ack --nogroup -- "
+(defcustom ack-command "ack -- "
   "The default ack command for \\[ack].
 
-Make sure --nogroup is present otherwise some commands may not
-work as expected.
-
 Note also options to ack can be specified in ACK_OPTIONS
 environment variable and ~/.ackrc, which you can disable by the
 --noenv switch."
@@ -57,6 +54,10 @@ environment variable and ~/.ackrc, which you can disable by 
the
 
 (defvar ack-history nil "History list for ack.")
 
+;; Used implicitly by `define-compilation-mode'
+(defvar ack-error "ack match"
+  "Stem of message to print when no matches are found.")
+
 (defun ack-filter ()
   "Handle match highlighting escape sequences inserted by the ack process.
 This function is called from `compilation-filter-hook'."
@@ -70,7 +71,8 @@ This function is called from `compilation-filter-hook'."
 
 ;; Used implicitly by `define-compilation-mode'
 (defvar ack-mode-font-lock-keywords
-  '(;; Command output lines.
+  '(("^--$" 0 'shadow)
+    ;; Command output lines.
     (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or 
directory\\|device or address\\)\\)$"
      1 'compilation-error)
     ;; remove match from ack-regexp-alist before fontifying
@@ -83,25 +85,40 @@ This function is called from `compilation-filter-hook'."
   "Additional things to highlight in ack output.
 This gets tacked on the end of the generated expressions.")
 
+(defun ack--column-start ()
+  (let* ((beg (match-end 0))
+         (end (save-excursion
+                (goto-char beg)
+                (line-end-position)))
+         (mbeg (text-property-any beg end 'ack-color t)))
+    (when mbeg (- mbeg beg))))
+
+(defun ack--column-end ()
+  (let* ((beg (match-end 0))
+         (end (save-excursion
+                (goto-char beg)
+                (line-end-position)))
+         (mbeg (text-property-any beg end 'ack-color t))
+         (mend (and mbeg (next-single-property-change
+                          mbeg 'ack-color nil end))))
+    (when mend (- mend beg))))
+
+(defun ack--file ()
+  (let (file)
+    (save-excursion
+      (forward-line -1)
+      (setq file (or (get-text-property (line-beginning-position) 'ack-file)
+                     (buffer-substring-no-properties
+                      (line-beginning-position) (line-end-position)))))
+    (put-text-property (line-beginning-position)
+                       (1+ (line-end-position)) 'ack-file file)
+    (list file)))
+
 (defconst ack-regexp-alist
-  '(("^\\(.+?\\):\\([1-9][0-9]*\\):\\(?:\\([1-9][0-9]*\\):\\)?"
-     1 2 ((lambda ()
-            (let* ((beg (match-end 0))
-                   (end (save-excursion
-                          (goto-char beg)
-                          (line-end-position)))
-                   (mbeg (text-property-any beg end 'ack-color t)))
-              (when mbeg (- mbeg beg))))
-          .
-          (lambda ()
-            (let* ((beg (match-end 0))
-                   (end (save-excursion
-                          (goto-char beg)
-                          (line-end-position)))
-                   (mbeg (text-property-any beg end 'ack-color t))
-                   (mend (and mbeg (next-single-property-change
-                                    mbeg 'ack-color nil end))))
-              (when mend (- mend beg))))))
+  '(("^\\(.+?\\)\\(:\\|-\\)\\([1-9][0-9]*\\)\\2\\(?:\\([1-9][0-9]*\\)\\2\\)?"
+     1 3 (ack--column-start . ack--column-end))
+    ("^\\([1-9][0-9]*\\)\\(:\\|-\\)\\(?:[1-9][0-9]*\\2\\)?"
+     ack--file 1 (ack--column-start . ack--column-end))
     ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
   "Ack version of `compilation-error-regexp-alist' (which see).")
 

commit a365a334fff47210aec9544f56734022316d6656
Author: Leo Liu <address@hidden>
Date:   Sat Mar 24 15:56:23 2012 +0800

    Some tweaks to README
    
    Thanks to scottj (#emacs) for suggestions.

diff --git a/README b/README
index aab257c..486954a 100644
--- a/README
+++ b/README
@@ -10,3 +10,14 @@ From http://betterthangrep.com/
     Perl's regular expressions.
 
 Feature requests and bug reports are welcome. Thanks.
+
+Install
+----------
+
+Drop ack.el in the load-path and put (require 'ack) or (autoload 'ack
+"ack" nil t) in your .emacs.
+
+Usage
+----------
+
+M-x ack

commit d566eb777d6c0cd7dc09edc0b736dbe668668a2b
Author: Leo Liu <address@hidden>
Date:   Sat Mar 24 14:08:08 2012 +0800

    Initial import

diff --git a/README b/README
new file mode 100644
index 0000000..aab257c
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+Emacs Interface to command-line tool ack
+========================================
+
+From http://betterthangrep.com/
+
+    ack is a tool like grep, designed for programmers with large trees of
+    heterogeneous source code.
+    
+    ack is written purely in Perl, and takes advantage of the power of
+    Perl's regular expressions.
+
+Feature requests and bug reports are welcome. Thanks.
diff --git a/ack.el b/ack.el
new file mode 100644
index 0000000..8a3ec2c
--- /dev/null
+++ b/ack.el
@@ -0,0 +1,128 @@
+;;; ack.el --- Emacs interface to ack
+
+;; Copyright (C) 2012  Leo Liu
+
+;; Author: Leo Liu <address@hidden>
+;; Keywords: tools, processes, convenience
+;; Created: 2012-03-24
+;; Version: 0.5
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; ack is a tool like grep, designed for programmers with large trees
+;; of heterogeneous source code - http://betterthangrep.com/.
+
+;;; Code:
+
+(require 'compile)
+(require 'ansi-color)
+
+(defgroup ack nil
+  "Run `ack' and display the results."
+  :group 'tools
+  :group 'processes)
+
+;; Used implicitly by `define-compilation-mode'
+(defcustom ack-scroll-output nil
+  "Similar to `compilation-scroll-output' but for the *Ack* buffer."
+  :type 'boolean
+  :group 'ack)
+
+(defcustom ack-command "ack --nogroup -- "
+  "The default ack command for \\[ack].
+
+Make sure --nogroup is present otherwise some commands may not
+work as expected.
+
+Note also options to ack can be specified in ACK_OPTIONS
+environment variable and ~/.ackrc, which you can disable by the
+--noenv switch."
+  :type 'string
+  :group 'ack)
+
+;;; ======== END of USER OPTIONS ========
+
+(defvar ack-history nil "History list for ack.")
+
+(defun ack-filter ()
+  "Handle match highlighting escape sequences inserted by the ack process.
+This function is called from `compilation-filter-hook'."
+  (save-excursion
+    (let ((ansi-color-apply-face-function
+           (lambda (beg end face)
+             (when face
+               (ansi-color-apply-overlay-face beg end face)
+               (put-text-property beg end 'ack-color t)))))
+      (ansi-color-apply-on-region compilation-filter-start (point)))))
+
+;; Used implicitly by `define-compilation-mode'
+(defvar ack-mode-font-lock-keywords
+  '(;; Command output lines.
+    (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or 
directory\\|device or address\\)\\)$"
+     1 'compilation-error)
+    ;; remove match from ack-regexp-alist before fontifying
+    ("^Ack \\(?:started\\|finished at\\).*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
+    ("^Ack \\(exited 
abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code 
\\([0-9]+\\)\\)?.*"
+     (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
+     (1 'compilation-error)
+     (2 'compilation-error nil t)))
+  "Additional things to highlight in ack output.
+This gets tacked on the end of the generated expressions.")
+
+(defconst ack-regexp-alist
+  '(("^\\(.+?\\):\\([1-9][0-9]*\\):\\(?:\\([1-9][0-9]*\\):\\)?"
+     1 2 ((lambda ()
+            (let* ((beg (match-end 0))
+                   (end (save-excursion
+                          (goto-char beg)
+                          (line-end-position)))
+                   (mbeg (text-property-any beg end 'ack-color t)))
+              (when mbeg (- mbeg beg))))
+          .
+          (lambda ()
+            (let* ((beg (match-end 0))
+                   (end (save-excursion
+                          (goto-char beg)
+                          (line-end-position)))
+                   (mbeg (text-property-any beg end 'ack-color t))
+                   (mend (and mbeg (next-single-property-change
+                                    mbeg 'ack-color nil end))))
+              (when mend (- mend beg))))))
+    ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
+  "Ack version of `compilation-error-regexp-alist' (which see).")
+
+(define-compilation-mode ack-mode "Ack"
+  "A compilation mode tailored for ack."
+  (set (make-local-variable 'compilation-disable-input) t)
+  (set (make-local-variable 'compilation-error-face)
+       'compilation-info)
+  (set (make-local-variable 'compilation-error-regexp-alist)
+       ack-regexp-alist)
+  (add-hook 'compilation-filter-hook 'ack-filter nil t))
+
+;;;###autoload
+(defun ack (command-args)
+  "Run ack using COMMAND-ARGS and collect output in a buffer.
+
+\\{ack-mode-map}"
+  (interactive
+   (list (read-from-minibuffer "Run ack (like this): "
+                               ack-command nil nil 'ack-history)))
+  (compilation-start command-args 'ack-mode))
+
+(provide 'ack)
+;;; ack.el ends here

commit 958953e814d802c998186f3e3535eab7a65bdd65
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Mar 22 16:51:57 2012 +0000

    Add documentation for f90-list-in-scope-vars

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index b12a6c1..5746b51 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -47,6 +47,12 @@
 ;; so that you can use it on the M-.  keybinding and it will fall back
 ;; to completing tag names if you don't want to look for an interface
 ;; definition.
+;; In addition, if you're in a large procedure and want the list of
+;; the variables in scope (perhaps you want to define a new loop
+;; variable), you can use `f90-list-in-scope-vars' to pop up a buffer
+;; giving a reasonable guess.  Note this doesn't give you module
+;; variables, or the variables of parent procedures if the current
+;; subroutine is contained within another.
 
 ;; Derived types are also parsed, so that slot types of derived types
 ;; are given the correct type (rather than a UNION-TYPE) when arglist
@@ -900,6 +906,9 @@ needs a reference count interface, so insert one."
               (forward-line 1))
             (when (not (looking-at "^\\s-*$"))
               (setq type (ignore-errors (f90-parse-single-type-declaration)))
+              ;; If we were on a line with text and failed to parse a
+              ;; type, we must have reached the end of the type
+              ;; definitions, so don't push it on and finish.
               (if type
                   (push type types)
                 (setq not-done nil)))
@@ -908,6 +917,7 @@ needs a reference count interface, so insert one."
       (setq buffer-read-only nil)
       (erase-buffer)
       (f90-mode)
+      ;; Show types of the same type together
       (setq types (sort types (lambda (x y)
                                 (string< (cadar x) (cadar y)))))
       (loop for (type name) in types

commit 933142ff5838718f683e6855ed0a7e7f82c1d3a1
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Mar 22 16:51:17 2012 +0000

    Skip over implicit none in procedure var parsing
    
    A procedure may start with "implicit none" which defeated our
    heuristic for deciding when we'd reached the end of a variable
    declaration block.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index b4f42bf..b12a6c1 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -895,6 +895,9 @@ needs a reference count interface, so insert one."
         (let ((not-done t)
               type)
           (while (and not-done (not (eobp)))
+            ;; skip "implicit none" which may appear at top of procedure
+            (when (looking-at "\\s-*implicit\\s-+none")
+              (forward-line 1))
             (when (not (looking-at "^\\s-*$"))
               (setq type (ignore-errors (f90-parse-single-type-declaration)))
               (if type

commit f3ea216b69d0dc583b63b7a854155caa739a2aaf
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Mar 22 16:31:59 2012 +0000

    New function f90-list-in-scope-vars
    
    Create a buffer showing the list of variables in scope in the current
    procedure.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index eb17e39..b4f42bf 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -878,6 +878,44 @@ needs a reference count interface, so insert one."
           (goto-char (point-min))
           (f90-arg-types names))))))
 
+(defun f90-list-in-scope-vars ()
+  "Pop up a buffer showing all variables in scope in the procedure at `point'"
+  (interactive)
+  (let* ((e (save-excursion (f90-end-of-subprogram) (point)))
+         (b (save-excursion (f90-beginning-of-subprogram) (point)))
+         (str (buffer-substring-no-properties b e))
+         types)
+    (with-temp-buffer
+      (with-syntax-table f90-mode-syntax-table
+        (insert str)
+        (goto-char (point-min))
+        (f90-clean-comments)
+        (f90-clean-continuation-lines)
+        (forward-line 1)                ; skip procedure name
+        (let ((not-done t)
+              type)
+          (while (and not-done (not (eobp)))
+            (when (not (looking-at "^\\s-*$"))
+              (setq type (ignore-errors (f90-parse-single-type-declaration)))
+              (if type
+                  (push type types)
+                (setq not-done nil)))
+            (forward-line 1)))))
+    (with-current-buffer (get-buffer-create "*Variables in scope*")
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (f90-mode)
+      (setq types (sort types (lambda (x y)
+                                (string< (cadar x) (cadar y)))))
+      (loop for (type name) in types
+            do
+            (insert (format "%s :: %s\n"
+                            (f90-format-parsed-slot-type type)
+                            (f90-get-parsed-type-varname type))))
+      (pop-to-buffer (current-buffer))
+      (goto-char (point-min))
+      (setq buffer-read-only t))))
+
 (defun f90-arg-types (names)
   "Given NAMES of arguments return their types.
 

commit 5980a3cafe18061365b92222282ead155a639b67
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 11 21:06:03 2012 +0100

    (ioccur-read-search-input): Fix kill and yank.

diff --git a/ioccur.el b/ioccur.el
index 57459fa..fcb0165 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -689,12 +689,12 @@ START-POINT is the point where we start searching in 
buffer."
                            (setq cur-hist-elm (ioccur-iter-next it))
                            (setq tmp-list nil)
                            (loop for char across cur-hist-elm
-                              do (push char tmp-list))
+                                 do (push char tmp-list))
                            (setq ioccur-pattern cur-hist-elm)))
                        ;; First call use car of history ring.
                        (setq tmp-list nil)
                        (loop for char across cur-hist-elm
-                          do (push char tmp-list))
+                             do (push char tmp-list))
                        (setq ioccur-pattern cur-hist-elm)
                        (setq start-hist t)))
                  (message "No history available.") (sit-for 2) t))
@@ -703,7 +703,7 @@ START-POINT is the point where we start searching in 
buffer."
            (insert-initial-input ()
              (unless (string= initial-input "")
                (loop for char across initial-input
-                  do (push char tmp-list))))
+                     do (push char (nthcdr index tmp-list)))))
            ;; Maybe start timer.
            ;;
            (start-timer ()
@@ -720,7 +720,7 @@ START-POINT is the point where we start searching in 
buffer."
              (with-current-buffer ioccur-current-buffer
                (goto-char start-point)
                (setq yank-point start-point))
-             (kill-new (substring str (- (1- (length tmp-list)) index)))
+             (kill-new (substring str (- (length tmp-list) index)))
              (setq tmp-list (nthcdr index tmp-list)))
            ;; Add cursor in minibuffer
            ;;

commit b548323ad63f9ba192433866bb5e1ce8145a7174
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 10 19:12:24 2012 +0100

    (ioccur-read-search-input): Use with-no-warnings with pop.
    (ioccur): Fix docstring.

diff --git a/ioccur.el b/ioccur.el
index 05719ce..57459fa 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -771,7 +771,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (with-current-buffer ioccur-current-buffer
                     (goto-char start-point)
                     (setq yank-point start-point))
-                  (setf (nthcdr index tmp-list) (cdr (nthcdr index tmp-list)))
+                  (with-no-warnings (pop (nthcdr index tmp-list)))
                   t)
                  (?\C-g                         ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
@@ -882,6 +882,7 @@ C-j or <left>      Jump and kill `ioccur-buffer'.\n
 RET                Exit keeping `ioccur-buffer'.\n
 DEL                Remove last character entered.\n
 C-k                Kill current input.\n
+C-a/e/b/f          Movements in minibuffer.\n
 M-k/C-x            Kill current input as sexp.\n
 C-w                Yank stuff at point.\n
 C-g                Quit and restore buffer.\n
@@ -942,8 +943,9 @@ C-z or <right> jump without quitting loop.
 C-j or <left>  jump and kill `ioccur-buffer'.
 RET            exit keeping `ioccur-buffer'.
 DEL            remove last character entered.
-C-k            Kill current input.
-M-k             Kill current input as sexp.
+C-k            Kill current input from cursor to eol.
+C-a/e/b/f      Movements in minibuffer.
+M-k            Kill current input as sexp.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
 C-s            Toggle split window.

commit 1d2aed3624fc3125f59d0dc0ec6aec531533574b
Author: Chris Wanstrath <address@hidden>
Date:   Thu Mar 8 12:11:35 2012 -0800

    Use correct URL. Fixes #71

diff --git a/coffee-mode.el b/coffee-mode.el
index b93cd32..0f1ec91 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -5,7 +5,7 @@
 ;; Version: 0.4.0
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
-;; URL: http://github.com/defunkt/coffee-script
+;; URL: http://github.com/defunkt/coffee-mode
 
 ;; This file is not part of GNU Emacs.
 

commit ee88fdc026b0c558934b57c029f46a009b066cf1
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 8 19:06:54 2012 +0100

    (ioccur-read-search-input): kill from current position with C-k.

diff --git a/ioccur.el b/ioccur.el
index 0ddc29a..05719ce 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -720,7 +720,8 @@ START-POINT is the point where we start searching in 
buffer."
              (with-current-buffer ioccur-current-buffer
                (goto-char start-point)
                (setq yank-point start-point))
-             (kill-new str) (setq tmp-list ()))
+             (kill-new (substring str (- (1- (length tmp-list)) index)))
+             (setq tmp-list (nthcdr index tmp-list)))
            ;; Add cursor in minibuffer
            ;;
            (set-cursor (str pos)

commit 3e79a006b3a315096bd09a95b53a625add9662ae
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 8 18:34:37 2012 +0100

    (ioccur-read-search-input): Add C-a and C-e.

diff --git a/ioccur.el b/ioccur.el
index 7bbbb69..0ddc29a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -770,7 +770,6 @@ START-POINT is the point where we start searching in 
buffer."
                   (with-current-buffer ioccur-current-buffer
                     (goto-char start-point)
                     (setq yank-point start-point))
-                  ;(pop (nthcdr index tmp-list))
                   (setf (nthcdr index tmp-list) (cdr (nthcdr index tmp-list)))
                   t)
                  (?\C-g                         ; Quit and restore buffers.
@@ -843,6 +842,10 @@ START-POINT is the point where we start searching in 
buffer."
                   (setq index (min (1+ index) (length tmp-list))) t)
                  (?\C-f                         ; forward-char.
                   (setq index (max (1- index) 0)) t)
+                 (?\C-a                         ; move bol.
+                  (setq index (length tmp-list)) t)
+                 (?\C-e                         ; move eol.
+                  (setq index 0) t)
                  (t                             ; Store character.
                   (start-timer)
                   (if (characterp char)

commit 9a773dfe4bfa970a0734b47eaf6a4394559a6571
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 8 18:34:04 2012 +0100

    (ioccur-read-search-input): Introduce edition of minibuffer input. C-b, 
C-f, and a cursor in minibuffer.

diff --git a/ioccur.el b/ioccur.el
index 45d30a4..7bbbb69 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -186,6 +186,10 @@ Set it to non--nil if menu disapear or if keys are echoing 
in minibuffer.")
   "Face for highlight wrong regexp message in ioccur buffer."
   :group 'ioccur-faces)
 
+(defface ioccur-cursor
+    '((t (:foreground "green")))
+  "Face for cursor color in minibuffer."
+  :group 'ioccur-faces)
 
 ;;; Internal variables.
 ;; String entered in prompt.
@@ -650,7 +654,8 @@ START-POINT is the point where we start searching in 
buffer."
          (it-next        nil)
          (cur-hist-elm   (car ioccur-history))
          (start-hist     nil) ; Flag to notify if cycling history started.
-         yank-point)
+         yank-point
+         (index 0))
     (unless (string= initial-input "")
       (loop for char across initial-input do (push char tmp-list)))
     (setq ioccur-pattern initial-input)
@@ -715,10 +720,28 @@ START-POINT is the point where we start searching in 
buffer."
              (with-current-buffer ioccur-current-buffer
                (goto-char start-point)
                (setq yank-point start-point))
-             (kill-new str) (setq tmp-list ())))
+             (kill-new str) (setq tmp-list ()))
+           ;; Add cursor in minibuffer
+           ;;
+           (set-cursor (str pos)
+             (setq pos (min index (1- (length tmp-list))))
+             (when (not (string= str ""))
+               (let* ((real-index (- (1- (length tmp-list)) pos))
+                      (cur-str (substring str real-index (1+ real-index))))
+                 (concat (substring str 0 real-index)
+                         (propertize cur-str 'display
+                                     (if (= index (length tmp-list))
+                                         (concat
+                                          (propertize "|" 'face 'ioccur-cursor)
+                                          cur-str)
+                                         (concat
+                                          cur-str
+                                          (propertize "|" 'face 
'ioccur-cursor))))
+                         (substring str (1+ real-index)))))))
+      
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
-                          (concat prompt ioccur-pattern))))
+                          (concat prompt (set-cursor ioccur-pattern index)))))
                (message nil)
                (case char
                  ((not (?\M-p ?\M-n ?\t C-tab)) ; Reset history
@@ -747,7 +770,9 @@ START-POINT is the point where we start searching in 
buffer."
                   (with-current-buffer ioccur-current-buffer
                     (goto-char start-point)
                     (setq yank-point start-point))
-                  (pop tmp-list) t)
+                  ;(pop (nthcdr index tmp-list))
+                  (setf (nthcdr index tmp-list) (cdr (nthcdr index tmp-list)))
+                  t)
                  (?\C-g                         ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
                  ((right ?\C-z)                 ; Persistent action.
@@ -769,7 +794,7 @@ START-POINT is the point where we start searching in 
buffer."
                       (setq ioccur-search-function 're-search-forward)) t)
                  (?\C-k                         ; Kill input.
                   (start-timer)
-                  (kill ioccur-pattern) t)
+                  (kill ioccur-pattern) (setq index 0) t)
                  ((?\M-k ?\C-x)                 ; Kill input as sexp.
                   (start-timer)
                   (let ((sexp (prin1-to-string ioccur-pattern)))
@@ -799,11 +824,13 @@ START-POINT is the point where we start searching in 
buffer."
                         (insert-initial-input)))) t)
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
+                  (setq index 0)
                   (cycle-hist -1))
                  ((backtab ?\M-n)               ; Next history elm.
                   (start-timer)
+                  (setq index 0)
                   (cycle-hist 1))
-                 (?\C-q                         ; quoted-insert
+                 (?\C-q                         ; quoted-insert.
                   (stop-timer)
                   (let ((char (with-temp-buffer
                                 (call-interactively 'quoted-insert)
@@ -811,10 +838,15 @@ START-POINT is the point where we start searching in 
buffer."
                     (push (string-to-char char) tmp-list))
                   (start-timer)
                   t)
+                 ;; Movements in minibuffer
+                 (?\C-b                         ; backward-char.
+                  (setq index (min (1+ index) (length tmp-list))) t)
+                 (?\C-f                         ; forward-char.
+                  (setq index (max (1- index) 0)) t)
                  (t                             ; Store character.
                   (start-timer)
                   (if (characterp char)
-                      (push char tmp-list)
+                      (push char (nthcdr index tmp-list))
                       (setq unread-command-events
                             (nconc (mapcar 'identity
                                            (this-single-command-raw-keys))

commit 1f2ecc016c9cde8e26c6c550c950263d33a859bc
Merge: 1591d68 18d7789
Author: Masafumi Oyamada <address@hidden>
Date:   Wed Mar 7 20:35:14 2012 -0800

    Merge pull request #37 from eentzel/master
    
    Consider foo.bar to be a single parameter name in jsdoc comments


commit 18d77895b945481a4b2354b9f3d445cf33a38844
Author: Eric Entzel <address@hidden>
Date:   Thu Mar 8 11:45:03 2012 +1100

    Consider foo.bar to be a single parameter name in jsdoc comments

diff --git a/js2-mode.el b/js2-mode.el
index 7deb55b..eaef485 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6479,7 +6479,7 @@ of a simple name.  Called before EXPR has a parent node."
           "\\(?:param\\|argument\\)"
           "\\)"
           "\\s-*\\({[^}]+}\\)?"         ; optional type
-          "\\s-*\\[?\\([a-zA-Z0-9_$]+\\)?\\]?"  ; name
+          "\\s-*\\[?\\([a-zA-Z0-9_$\.]+\\)?\\]?"  ; name
           "\\>")
   "Matches jsdoc tags with optional type and optional param name.")
 

commit 1591d685c36a8bba463b8846323ef5cc3d71fd99
Merge: 4c008b1 737760e
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 12 20:53:58 2012 -0800

    Merge pull request #36 from edmccard/master
    
    Don't make `before-save-hook` a local variable


commit 737760e7a910e814759cd79b01bb3eddc86c010b
Author: Ed McCardell <address@hidden>
Date:   Sun Feb 12 22:28:52 2012 -0500

    Play nice with global before-save-hook

diff --git a/js2-mode.el b/js2-mode.el
index 115cbc1..7deb55b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10421,7 +10421,7 @@ If so, we don't ever want to use bounce-indent."
   ;; So it's back to `c-fill-paragraph'.
   (set (make-local-variable 'fill-paragraph-function) #'c-fill-paragraph)
 
-  (set (make-local-variable 'before-save-hook) #'js2-before-save)
+  (add-hook 'before-save-hook #'js2-before-save nil t)
   (set (make-local-variable 'next-error-function) #'js2-next-error)
   (set (make-local-variable 'beginning-of-defun-function) 
#'js2-beginning-of-defun)
   (set (make-local-variable 'end-of-defun-function) #'js2-end-of-defun)

commit cd7950c7720d2f631741e543e24f1ed9cf4e3883
Author: Dmitry Gutov <address@hidden>
Date:   Mon Feb 13 06:12:02 2012 +0400

    Rework js2-beginning/end-of-defun
    
    js2-end-of-defun:
    * Jump over all script-level elements one at a time, not only functions, for
      consistency with `js2-mark-defun` and `js2-beginning-of-defun`.
    * Don't jump to after the next function when point is on "function" keyword.
    
    js2-beginning-of-defun:
    * Handle the optional argument like `beginning-of-defun` does.

diff --git a/js2-mode.el b/js2-mode.el
index 115cbc1..77074d7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4460,7 +4460,7 @@ Returns nil if no applicable child is found."
         result
         fn
         (continue t))
-    (setq fn (if after '> '<))
+    (setq fn (if after '>= '<))
     (while (and kids continue)
       (setq kid (car kids))
       (if (funcall fn (+ beg (js2-node-pos kid)) pos)
@@ -11533,29 +11533,45 @@ Parent is defined as the enclosing script or 
function."
     (when (setq sib (js2-node-find-child-before (point) parent))
       (goto-char (js2-node-abs-pos sib)))))
 
-(defun js2-beginning-of-defun ()
-  "Go to line on which current function starts, and return non-nil.
-If we're not in a function, go to beginning of previous script-level element."
-  (interactive)
-  (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point)))
-        pos sib)
-    (cond
-     ((and (js2-function-node-p parent)
-           (not (eq (point) (setq pos (js2-node-abs-pos parent)))))
-      (goto-char pos))
-     (t
-      (js2-mode-backward-sibling)))))
+(defun js2-beginning-of-defun (&optional arg)
+  "Go to line on which current function starts, and return t on success.
+If we're not in a function or already at the beginning of one, go
+to beginning of previous script-level element.
+With ARG N, do that N times. If N is negative, move "
+  (setq arg (or arg 1))
+  (if (plusp arg)
+      (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point))))
+        (when (cond
+               ((js2-function-node-p parent)
+                (goto-char (js2-node-abs-pos parent)))
+               (t
+                (js2-mode-backward-sibling)))
+          (if (> arg 1)
+              (js2-beginning-of-defun (1- arg))
+            t)))
+    (when (js2-end-of-defun)
+      (if (>= arg -1)
+          (js2-beginning-of-defun 1)
+        (js2-beginning-of-defun (1+ arg))))))
 
 (defun js2-end-of-defun ()
-  "Go to the char after the last position of the current function.
-If we're not in a function, skips over the next script-level element."
-  (interactive)
-  (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point))))
-    (if (not (js2-function-node-p parent))
-        ;; punt:  skip over next script-level element beyond point
-        (js2-mode-forward-sibling)
-      (goto-char (+ 1 (+ (js2-node-abs-pos parent)
-                         (js2-node-len parent)))))))
+  "Go to the char after the last position of the current function
+or script-level element."
+  (let* ((node (js2-node-at-point))
+         (parent (or (and (js2-function-node-p node) node)
+                     (js2-node-parent-script-or-fn node)))
+         script)
+    (unless (js2-function-node-p parent)
+      ;; use current script-level node, or, if none, the next one
+      (setq script (or parent node))
+      (setq parent (js2-node-find-child-before (point) script))
+      (when (or (null parent)
+                (>= (point) (+ (js2-node-abs-pos parent)
+                               (js2-node-len parent))))
+        (setq parent (js2-node-find-child-after (point) script))))
+    (when parent
+      (goto-char (+ (js2-node-abs-pos parent)
+                    (js2-node-len parent))))))
 
 (defun js2-mark-defun (&optional allow-extend)
   "Put mark at end of this function, point at beginning.

commit 4c008b1987aa53769899e24808b6d74b41b4ff40
Author: Dmitry Gutov <address@hidden>
Date:   Mon Jan 30 18:16:58 2012 +0400

    Link to js2-refactor

diff --git a/README.md b/README.md
index 556b32c..3964091 100644
--- a/README.md
+++ b/README.md
@@ -34,4 +34,4 @@ See Also
 Some third-party modes that use the generated syntax tree:
 
 * 
[js2-highlight-vars-mode](http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode)
-* 
[js2-rename-var](https://github.com/magnars/mark-multiple.el/blob/master/js2-rename-var.el)
+* [js2-refactor](https://github.com/magnars/js2-refactor.el)

commit a1a452af1889235a9ec3cef2cbdd3f67fe70f2ef
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Jan 26 16:58:21 2012 +0000

    Doc updates, version header

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 49d84b3..eb17e39 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -5,6 +5,8 @@
 ;; Copyright (C) 2011 Lawrence Mitchell <address@hidden>
 ;; Filename: f90-interface-browser.el
 ;; Created: 2011-07-06
+;; Available-from: http://github.com/wence-/f90-iface/
+;; Version: 1.0
 
 ;; COPYRIGHT NOTICE
 
@@ -91,6 +93,9 @@
 ;; modifiers, like integer(kind=c_int), for which the precision is
 ;; just ignored, and many other aspects.
 
+;; Some tests of the parser are available in f90-tests.el (in the same
+;; repository as this file).
+
 ;;; Code:
 
 ;;; Preamble

commit 4572c4be9dcb5c4fcac7426d4954d4451223851c
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Jan 26 13:10:06 2012 +0000

    Fix up precision modifiers to base types
    
    Previously we would parse character(len=*) as different from
    character(len=128) and also integer(kind=c_int) as different from
    integer.  Now we just throw the modifier away entirely.  This gives us
    more false positives, but fewer false negatives when matching, which
    is probably worthwhile.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 17afb41..49d84b3 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -88,8 +88,8 @@
 ;;    end subroutine bar
 
 ;; Also not handled are overloaded operators, scalar precision
-;; modifiers (integer(kind=foo_integer) and the like) and many other
-;; aspects.
+;; modifiers, like integer(kind=c_int), for which the precision is
+;; just ignored, and many other aspects.
 
 ;;; Code:
 
@@ -991,13 +991,15 @@ dealt with correctly."
 This takes the bit before the :: and returns a list of the typename
 and any modifiers."
   (let ((things (f90-split-arglist dec)))
-    (cons (car things)
+    (cons (if (string-match
+               "\\([^(]+?\\)[ \t]*([ \t]*\\(:?len\\|kind\\)[ \t]*=[^)]+)"
+               (car things))
+              (match-string 1 (car things))
+            (car things))
           (loop for thing in (cdr things)
                 if (string-match "dimension[ \t]*(\\(.+\\))" thing)
                 collect (cons "dimension"
                               (1+ (f90-count-commas (match-string 1 thing))))
-                else if (string-match "character([^)]+)" thing)
-                collect (cons "character" "*")
                 else
                 collect thing))))
 
diff --git a/f90-tests.el b/f90-tests.el
index 30020b6..d653882 100644
--- a/f90-tests.el
+++ b/f90-tests.el
@@ -55,6 +55,7 @@
   (test-check
    ((f90-split-declaration "integer") ("integer"))
    ((f90-split-declaration "integer, pointer") ("integer" "pointer"))
+   ((f90-split-declaration "integer (kind = c_int(8)   )") ("integer"))
    ((f90-split-declaration "character(len=*)") ("character"))
    ((f90-split-declaration "integer, dimension(:)")
     ("integer" ("dimension" . 1)))))

commit 029dd7e006c850883026be022ce09c7e0ac60d57
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jan 25 23:24:55 2012 +0400

    Fix fill-paragraph behavior
    
    Closes #34

diff --git a/js2-mode.el b/js2-mode.el
index 9b782ee..115cbc1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10417,9 +10417,8 @@ If so, we don't ever want to use bounce-indent."
   (set (make-local-variable 'indent-region-function) #'js2-indent-region)
 
   ;; I tried an "improvement" to `c-fill-paragraph' that worked out badly
-  ;; on most platforms other than the one I originally wrote it on.  So it's
-  ;; back to `c-fill-paragraph'.  Still not perfect, though -- something to do
-  ;; with our binding of the RET key inside comments:  short lines stay short.
+  ;; on most platforms other than the one I originally wrote it on.
+  ;; So it's back to `c-fill-paragraph'.
   (set (make-local-variable 'fill-paragraph-function) #'c-fill-paragraph)
 
   (set (make-local-variable 'before-save-hook) #'js2-before-save)
@@ -10435,9 +10434,9 @@ If so, we don't ever want to use bounce-indent."
   (put 'js2-mode 'find-tag-default-function #'js2-mode-find-tag)
 
   ;; some variables needed by cc-engine for paragraph-fill, etc.
-  (setq c-buffer-is-cc-mode t
-        c-comment-prefix-regexp js2-comment-prefix-regexp
+  (setq c-comment-prefix-regexp js2-comment-prefix-regexp
         c-comment-start-regexp "/[*/]\\|\\s|"
+        c-line-comment-starter "//"
         c-paragraph-start js2-paragraph-start
         c-paragraph-separate "$"
         comment-start-skip js2-comment-start-skip
@@ -10445,6 +10444,15 @@ If so, we don't ever want to use bounce-indent."
         c-syntactic-ws-end js2-syntactic-ws-end
         c-syntactic-eol js2-syntactic-eol)
 
+  (let ((c-buffer-is-cc-mode t))
+    ;; Copied from `js-mode'.  Also see Bug#6071.
+    (make-local-variable 'paragraph-start)
+    (make-local-variable 'paragraph-separate)
+    (make-local-variable 'paragraph-ignore-fill-prefix)
+    (make-local-variable 'adaptive-fill-mode)
+    (make-local-variable 'adaptive-fill-regexp)
+    (c-setup-paragraph-variables))
+
   (setq js2-default-externs
         (append js2-ecma-262-externs
                 (if js2-include-browser-externs

commit c42b4f34fec4e69e632dfbea2e98968b1eda020f
Author: Lawrence Mitchell <address@hidden>
Date:   Wed Jan 25 18:37:50 2012 +0000

    Add more documentation and make Fluidity checks more generic

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 888c803..17afb41 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -38,43 +38,68 @@
 
 ;; Now you are able to browse (with completion) all defined interfaces
 ;; in your code by calling `f90-browse-interface-specialisers'.
-;; Alternatively, if `point' is on a function or subroutine call, you
-;; can call `f90-find-tag-interface' and you'll be shown a list of the
+;; Alternatively, if `point' is on a procedure call, you can call
+;; `f90-find-tag-interface' and you'll be shown a list of the
 ;; interfaces that match the (possibly typed) argument list of the
-;; current function.  This latter hooks into the `find-tag' machinery
-;; so that you can use it on the M-. keybinding and it will fall back
+;; current procedure.  This latter hooks into the `find-tag' machinery
+;; so that you can use it on the M-.  keybinding and it will fall back
 ;; to completing tag names if you don't want to look for an interface
 ;; definition.
 
 ;; Derived types are also parsed, so that slot types of derived types
 ;; are given the correct type (rather than a UNION-TYPE) when arglist
-;; matching.  You can show the definition of a know derived type by
+;; matching.  You can show the definition of a known derived type by
 ;; calling `f90-show-type-definition' which prompts (with completion)
 ;; for a typename to show.
 
-;; The parsing is by no means complete, it does a half-hearted attempt
-;; using regular expressions (now you have two problems) rather than
-;; defining a grammar and doing full parsing.
+;; The parser assumes you write Fortran in the style espoused in
+;; Metcalf, Reid and Cohen.  Particularly, variable declarations use a
+;; double colon to separate the type from the name list.
+
+;; Here's an example of a derived type definition
+;;     type foo
+;;        real, allocatable, dimension(:) :: a
+;;        integer, pointer :: b, c(:)
+;;        type(bar) :: d
+;;     end type
+
+;; Here's a subroutine declaration
+;;     subroutine foo(a, b)
+;;        integer, intent(in) :: a
+;;        real, intent(inout), dimension(:,:) :: b
+;;        ...
+;;     end subroutine foo
+
+;; Local procedures whose names conflict with global ones will likely
+;; confuse the parser.  For example
+
+;;    subroutine foo(a, b)
+;;       ...
+;;    end subroutine foo
+;;
+;;    subroutine bar(a, b)
+;;       ...
+;;       call subroutine foo
+;;       ...
+;;     contains
+;;       subroutine foo
+;;          ...
+;;       end subroutine foo
+;;    end subroutine bar
+
+;; Also not handled are overloaded operators, scalar precision
+;; modifiers (integer(kind=foo_integer) and the like) and many other
+;; aspects.
 
 ;;; Code:
 
 ;;; Preamble
-(require 'cl)
+(eval-when-compile
+  (require 'cl))
 (require 'thingatpt)
 (require 'f90)
 (require 'etags)
 
-(defstruct f90-interface
-  (name "" :read-only t)
-  (publicp nil)
-  specialisers)
-
-(defstruct f90-specialiser
-  (name "" :read-only t)
-  (type "")
-  (arglist "")
-  location)
-
 (defgroup f90-iface nil
   "Static parser for Fortran 90 code"
   :prefix "f90-"
@@ -85,6 +110,28 @@
   :type '(repeat string)
   :group 'f90-iface)
 
+(defcustom f90-file-name-check-functions '(f90-check-fluidity-refcount)
+  "List of functions to call to check if a file should be parsed.
+
+In addition to checking if a file exists and is readable, you can
+add extra checks before deciding to parse a file.  Each function
+will be called with one argument, the fully qualified name of the
+file to test, it should return non-nil if the file should be
+parsed.  For an example test function see
+`f90-check-fluidity-refcount'."
+  :type '(repeat function)
+  :group 'f90-iface)
+
+(defcustom f90-extra-file-functions '(f90-insert-fluidity-refcount)
+  "List of functions to call to insert extra files to parse.
+
+Each function should be a function of two arguments, the first is the
+fully qualified filename (with directory) the second is the
+unqualified filename."
+  :type '(repeat function)
+  :group 'f90-iface)
+
+;;; Internal variables
 (defvar f90-interface-type nil)
 (make-variable-buffer-local 'f90-interface-type)
 
@@ -94,6 +141,18 @@
 (defvar f90-invocation-marker nil)
 (make-variable-buffer-local 'f90-invocation-marker)
 
+;; Data types for storing interface and specialiser definitions
+(defstruct f90-interface
+  (name "" :read-only t)
+  (publicp nil)
+  specialisers)
+
+(defstruct f90-specialiser
+  (name "" :read-only t)
+  (type "")
+  (arglist "")
+  location)
+
 (defvar f90-all-interfaces (make-hash-table :test 'equal)
   "Hash table populated with all known f90 interfaces.")
 
@@ -101,7 +160,6 @@
   "Hash table populated with all known f90 derived types.")
 
 ;;; Inlineable utility functions
-
 (defsubst f90-specialisers (name interfaces)
   "Return all specialisers for NAME in INTERFACES."
   (f90-interface-specialisers (f90-get-interface name interfaces)))
@@ -141,6 +199,7 @@ level.  For example, a LEVEL of 0 counts top-level commas."
       (funcall fn (f90-get-type type)))))
 
 (defun f90-lazy-completion-table ()
+  "Lazily produce a completion table of all interfaces and tag names."
   (lexical-let ((buf (current-buffer)))
     (lambda (string pred action)
       (with-current-buffer buf
@@ -152,7 +211,7 @@ level.  For example, a LEVEL of 0 counts top-level commas."
 
 
 (defsubst f90-merge-into-tags-completion-table (ctable)
-  "Merge interface completions in CTABLE into `tags-completion-table'."
+  "Merge completions in CTABLE into the tags completion table."
   (if (or tags-file-name tags-table-list)
       (let ((table (tags-completion-table)))
         (maphash (lambda (k v)
@@ -165,7 +224,7 @@ level.  For example, a LEVEL of 0 counts top-level commas."
 (defsubst f90-extract-type-name (name)
   "Return the typename from NAME.
 
-If NAME matches type(TYPENAME) return TYPENAME, otherwise just NAME."
+If NAME is like type(TYPENAME) return TYPENAME, otherwise just NAME."
   (if (and name (string-match "\\`type(\\([^)]+\\))\\'" name))
       (match-string 1 name)
     name))
@@ -175,8 +234,10 @@ If NAME matches type(TYPENAME) return TYPENAME, otherwise 
just NAME."
 (defun f90-parse-all-interfaces (dir)
   "Parse all interfaces found in DIR and its subdirectories.
 
-Recurse over all directories below DIR and parse interfaces found
-within them using `f90-parse-interfaces-in-dir'."
+Recurse over all (non-hidden) directories below DIR and parse
+interfaces found within them using `f90-parse-interfaces-in-dir',
+a directory is considered hidden if it's name doesn't start with
+an alphanumeric character."
   (interactive "DParse files in tree: ")
   (let (dirs
        attrs
@@ -210,8 +271,10 @@ within them using `f90-parse-interfaces-in-dir'."
 (defun f90-find-tag-interface (name &optional match-sublist)
   "List all interfaces matching NAME.
 
-Restricts list to those matching the (possibly typed) arglist of the
-word at point.  For the description of MATCH-SUBLIST see
+Restricts list to those matching the (possibly typed) arglist of
+the word at point.  If MATCH-SUBLIST is non-nil, only check if
+the arglist is a sublist of the specialiser's arglist.  For more
+details see `f90-approx-arglist-match' and
 `f90-browse-interface-specialisers'."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
@@ -387,7 +450,7 @@ indicating where we were called from, for jumping back to 
with
   (setq buffer-read-only t)
   (set-buffer-modified-p nil))
 
-;;; Show type definition
+;;; Type definitions
 
 (defun f90-type-at-point ()
   "Return a guess for the type of the thing at `point'.
@@ -499,11 +562,11 @@ default is the type of the variable."
     (mapconcat 'identity
                (loop while (not (eobp))
                      collect (buffer-substring (line-beginning-position)
-                                               (- (line-end-position) 7))
+                                               (- (line-end-position)
+                                                  (length " :: foo")))
                      do (forward-line 1))
                "; ")))
 
-
 (defun f90-count-non-optional-args (arglist)
   "Count non-optional args in ARGLIST."
   (loop for arg in arglist
@@ -570,24 +633,56 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
 
 ;;; Entry point to parsing routines
 
+(defun f90-parse-file-p (file)
+  "Return non-nil if FILE should be parsed.
+
+This checks that FILE exists and is readable, and then calls
+additional test functions from `f90-file-name-check-functions'."
+  (and (file-exists-p file)
+       (file-readable-p file)
+       (loop for test in f90-file-name-check-functions
+             unless (funcall test file)
+             do (return nil)
+             finally (return t))))
+
+(defun f90-check-fluidity-refcount (file)
+  "Return nil if FILE is that of a Fluidity refcount template."
+  (let ((fname (file-name-nondirectory file)))
+    (and (not (string-match "\\`Reference_count_interface" fname))
+         (not (string-equal "Refcount_interface_templates.F90" fname))
+         (not (string-equal "Refcount_templates.F90" fname)))))
+
+(defun f90-maybe-insert-extra-files (file)
+  "Maybe insert extra files corresponding to FILE when parsing.
+
+To actually insert extra files, customize the variable
+`f90-extra-file-functions'.  For an example insertion function
+see `f90-insert-fluidity-refcount'."
+  (let ((fname (file-name-nondirectory file)))
+    (loop for fn in f90-extra-file-functions
+          do (funcall fn file fname))))
+
+(defun f90-insert-fluidity-refcount (file fname)
+  "Insert a Fluidity reference count template for FILE.
+
+If FNAME matches \\\\`Reference_count_.*\\\\.F90 then this file
+needs a reference count interface, so insert one."
+  (when (string-match "\\`Reference_count_\\([^\\.]+\\)\\.F90" fname)
+    (insert-file-contents-literally
+     (expand-file-name
+      (format "Reference_count_interface_%s.F90"
+              (match-string 1 fname))
+      (file-name-directory file)))))
+
 (defun f90-parse-interfaces (file existing)
   "Parse interfaces in FILE and merge into EXISTING interface data."
   (with-temp-buffer
-    (let ((interfaces (make-hash-table :test 'equal))
-          (fname (file-name-nondirectory file)))
-      ;; Fiddle things for Fluidity sources
-      (when (and (file-exists-p file)
-                 (file-readable-p file)
-                 (not (string-match "\\`Reference_count_interface" fname))
-                 (not (string-equal "Refcount_interface_templates.F90" fname))
-                 (not (string-equal "Refcount_templates.F90" fname)))
+    (let ((interfaces (make-hash-table :test 'equal)))
+      ;; Is this file valid for parsing
+      (when (f90-parse-file-p file)
         (insert-file-contents-literally file)
-        (when (string-match "\\`Reference_count_\\([^\\.]+\\)\\.F90" fname)
-          (insert-file-contents-literally
-           (expand-file-name
-            (format "Reference_count_interface_%s.F90"
-                    (match-string 1 fname))
-            (file-name-directory file))))
+        ;; Does this file have other parts elsewhere?
+        (f90-maybe-insert-extra-files file)
         ;; Easier if we don't have to worry about line wrap
         (f90-clean-comments)
         (f90-clean-continuation-lines)
@@ -813,7 +908,7 @@ with slot B of type REAL, then A%B is returned being a 
REAL)."
 (defun f90-split-arglist (arglist &optional level)
   "Split ARGLIST into words.
 
-Split based on top-level commas. e.g.
+Split based on top-level commas.  For example
 
   (f90-split-arglist \"foo, bar, baz(quux, zot)\")
     => (\"foo\" \"bar\" \"baz(quux, zot)\").

commit 5412c73802de5548274548740575e5b8b6a3a387
Merge: f33709e 977d8f9
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jan 24 10:07:32 2012 +0100

    Merge branchs


commit 977d8f92732ce3642e122d3a6c2956339b65bc10
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jan 24 10:01:34 2012 +0100

    (ioccur-buffer-completion-use-ido): Renamed from 
`ioccur-buffer-completion-style'.
    When nil and ac-mode is turned on, use automatically anything completion.

diff --git a/ioccur.el b/ioccur.el
index 3a55159..45d30a4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -89,12 +89,12 @@
 
 ;;; User variables.
 (defcustom ioccur-search-delay 0.5
-  "*During incremental searching, display is updated all these seconds."
+  "During incremental searching, display is updated all these seconds."
   :group 'ioccur
   :type  'integer)
 
 (defcustom ioccur-search-prompt "Pattern: "
-  "*Prompt used for `ioccur-occur'."
+  "Prompt used for `ioccur-occur'."
   :group 'ioccur
   :type  'string)
 
@@ -106,57 +106,48 @@ C-k/x:Kill(as 
sexp),M-p/n:Hist,C/M-v:Scroll,C-down/up:Follow,C-w:Yank tap"
       " RET:Exit,C-g:Quit,C-j:Jump&quit,C-z:Jump,C-k/x:Kill(as sexp),\
 S-/Tab:Hist,C-v/t:Scroll,C-d/u:Follow,C-w:Yank tap")
 
-  "*Minimal documentation of `ioccur' commands displayed in mode-line.
+  "Minimal documentation of `ioccur' commands displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
   :type  'string)
 
 (defcustom ioccur-length-line 80
-  "*Length of the line displayed in ioccur buffer.
+  "Length of the line displayed in ioccur buffer.
 When set to nil lines displayed in `ioccur-buffer' will not be modified.
 See `ioccur-truncate-line'."
   :group 'ioccur
   :type 'integer)
 
 (defcustom ioccur-max-length-history 100
-  "*Maximum number of element stored in `ioccur-history'."
+  "Maximum number of element stored in `ioccur-history'."
   :group 'ioccur
   :type 'integer)
 
-(defcustom ioccur-buffer-completion-style 'anything
-  "*Type of completing read style you prefer to choose buffers \
-in `ioccur-find-buffer-matching'.
-It can be one of 'anything or 'ido.
-When nil or if anything is not found or `ido-mode' is off,
-fallback to classic `completing-read'.
-NOTE:
-To have anything completion you need a recent version of
-`anything-config.el'.
-To have ido completion, you have to enable `ido-mode'."
+(defcustom ioccur-buffer-completion-use-ido nil
+  "Use ido to choose buffers in `ioccur-find-buffer-matching'."
   :group 'ioccur
   :type 'symbol)
 
 (defcustom ioccur-default-search-function 're-search-forward
-  "*Default search function.
+  "Default search function.
 Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'symbol)
 
 (defcustom ioccur-highlight-match-p t
-  "*Highlight matchs in `ioccur-buffer' when non--nil."
+  "Highlight matchs in `ioccur-buffer' when non--nil."
   :group 'ioccur
   :type 'boolean)
 
 (defcustom ioccur-fontify-buffer-p nil
-  "*Fontify `ioccur-current-buffer' when non--nil.
+  "Fontify `ioccur-current-buffer' when non--nil.
 This allow to have syntactic coloration in `ioccur-buffer' but
 it slow down the start of ioccur at first time on large buffers."
   :group 'ioccur
   :type 'boolean)
 
 (defvar ioccur-read-char-or-event-skip-read-key nil
-  "*Force not using `read-key' even if bounded.
-You should not have to set this yourself.
+  "Force not using `read-key' to read input in minibuffer even if bounded.
 Set it to non--nil if menu disapear or if keys are echoing in minibuffer.")
 
 ;;; Faces.
@@ -418,8 +409,8 @@ Hitting C-g in a `ioccur' session will return to completion 
list.
 Hitting C-g in the completion list will jump back to initial buffer.
 
 The buffer completion list is provided by one of:
-`anything-comp-read', `ido-completing-read', `completing-read'
-depending on which `ioccur-buffer-completion-style' you have choosen."
+`ido-completing-read', `completing-read'
+depending on which `ioccur-buffer-completion-use-ido' you have choosen."
   ;; Remove doublons maybe added by minibuffer in `ioccur-history'.
   (setq ioccur-history
         (loop with hist for i in ioccur-history
@@ -436,13 +427,10 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
 
     (labels
         ((find-buffer ()
-           (let ((buf (cond ((and (fboundp 'anything-comp-read)
-                                  (eq ioccur-buffer-completion-style 
'anything))
-                             (anything-comp-read prompt buf-list :must-match 
t))
-                            ((and ido-mode
-                                  (eq ioccur-buffer-completion-style 'ido))
-                             (ido-completing-read prompt buf-list nil t))
-                            (t (completing-read prompt buf-list nil t)))))
+           (let ((buf (if (and ido-mode
+                               (eq ioccur-buffer-completion-use-ido 'ido))
+                          (ido-completing-read prompt buf-list nil t)
+                          (completing-read prompt buf-list nil t))))
              (unwind-protect
                   (progn
                     (switch-to-buffer buf)

commit 9a266d91c0cc15f10ec03c4ebb51e13952556384
Author: Dmitry Gutov <address@hidden>
Date:   Tue Jan 24 03:55:56 2012 +0400

    Update the README

diff --git a/README.md b/README.md
index 35d3ff5..556b32c 100644
--- a/README.md
+++ b/README.md
@@ -1,174 +1,37 @@
-js2-mode
-========
+Description
+======
 
 An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
 
-Install
-=======
+For the list of user-visible changes, see
+[Changes from the original 
mode](https://github.com/mooz/js2-mode/wiki/Changes-from-the-original-mode).
+
+Installation
+======
 
     $ git clone git://github.com/mooz/js2-mode.git
     $ cd js2-mode
     $ emacs --batch -f batch-byte-compile js2-mode.el
 
-_NOTE: Emacs may fail to byte compile js2-mode.el in interactive mode (e.g., 
`M-x byte-compile-file`). Following the above instruction is highly 
recommended. See https://github.com/mooz/js2-mode/issues/13 for details._
-
-Then, place js2-mode.elc into your site-lisp directory.
+Then put js2-mode.elc into your site-lisp directory.
 
 In you emacs config:
 
     (autoload 'js2-mode "js2-mode" nil t)
     (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
 
-See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for 
details.
-
-Differences between original js2-mode.el
-========================================
-
-Popular indentation style
--------------------------
-
-When `js2-consistent-level-indent-inner-bracket-p` is non-nil
-    
-    [foo, bar, baz].forEach(function (v) {
-        if (validate(v))
-            process(v);
-    });
-    
-    [a, b, c].some(function (v) {
-        return validate(v);
-    });
-
-When `js2-consistent-level-indent-inner-bracket-p` is nil
-(Same as original js2-mode's indentation)
-
-    [foo, bar, baz].forEach(function (v) {
-                                if (validate(v))
-                                    process(v);
-                            });
-    
-    [a, b, c].some(function (v) {
-                       return validate(v);
-                   });
-
-Pretty multi-line variable declaration
---------------------------------------
-
-In original js2-mode.el,
-
-    var foo = 10,
-    bar = 20,
-    baz = 30;
-
-In this js2-mode.el, when the value `js2-pretty-multiline-decl-indentation-p` 
is non-nil,
-
-    var foo = 10,
-        bar = 20,
-        baz = 30;
-
-Abbreviated destructuring assignments
--------------------------------------
-
-    let {a, b}       = {a: 10, b: 20}; // Abbreviated   (Not supported in 
original js2-mode.el)
-    let {a: a, b: b} = {a: 10, b: 20}; // Same as above (Supported in original 
js2-mode.el)
-
-    (function ({responseText}) { /* */ })(xhr); // As the argument of function
-
-    for (let [k, { name, age }] in Iterator(obj)) // nested
-        print(k, name, age);
-
-Expression closure in property value
-------------------------------------
-
-    let worker = {
-        get age() 20,
-        get sex() "male",
-        fire: function () _fire()
-    };
-
-Fix for odd indentation of "else if" with no braces
----------------------------------------------------
-
-In original js2-mode.el,
-
-    if (foo)
-        return foo;
-    else if (bar)
-    return bar;      // here
+See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for
+additional details.
 
-In this js2-mode.el,
-
-    if (foo)
-        return foo;
-    else if (bar)
-        return bar;  // fixed
-
-Fixes in Imenu support
-----------------------
-
-Supports element-get form:
-
-    foo["bar"] = function() {};
-    foo[647] = function() {};
-
-Proper position for functions in nested object literals:
-
-    foo = {
-        bar: function() {}, // ok in original
-        baz: {
-             boop: function() {} // fixed here
-        }
-    }
-
-Imenu support for function nesting
-----------------------------------
-
-Supports function nesting and anonymous wrappers:
-
-    (function() {
-      var foo = function() {
-        function bar() { // shown as foo.bar.<definition-1>
-          function baz() {} // foo.bar.baz
-          var qux = function() {}; // foo.bar.quux
-        }
-      };
-    });
-
-Examples of output:
-
-* [jQuery 1.5](https://gist.github.com/845449)
-* [Underscore.js](https://gist.github.com/824262)
-* [Backbone.js](https://gist.github.com/824260)
-
-No support for library-specific extension methods like $.extend.
-
-Highlights undeclared/external variables
-----------------------------------------
-
-Original mode highlights them only on the left side of assignments:
-
-    var house;
-    hose = new House(); // highlights "hose"
-
-Here they are highlighted in all expressions:
-    
-    function feed(fishes, food) {
-        for each (var fish in fshes) { // highlights "fshes"
-            food.feed(fsh); // highlights "fsh"
-        }
-        hood.discard(); // highlights "hood"
-    }
+Bugs
+====
 
-Destructuring assignments and array comprehensions (JS 1.7) are supported:
+If you find problems, please report them at 
<http://github.com/mooz/js2-mode/issues>.
 
-    let three, [one, two] = [1, 2];
-    thee = one + two; // highlights "thee" 
+See Also
+======
 
-    function revenue(goods) {
-        // highlights "coast"
-        return [price - coast for each ({price, cost} in goods)].reduce(add);
-    }
-    
-Bugs
-====
+Some third-party modes that use the generated syntax tree:
 
-If you find problems, please report them to 
<http://github.com/mooz/js2-mode/issues>.
+* 
[js2-highlight-vars-mode](http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode/js2-highlight-vars-mode)
+* 
[js2-rename-var](https://github.com/magnars/mark-multiple.el/blob/master/js2-rename-var.el)

commit d2299029927cce69eb9c4faa0a88f99ed3e45997
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jan 21 07:33:26 2012 +0100

    (ioccur-fontify-buffer-p): Now default to nil.

diff --git a/ioccur.el b/ioccur.el
index 7b99ff7..3a55159 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -147,7 +147,7 @@ Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'boolean)
 
-(defcustom ioccur-fontify-buffer-p t
+(defcustom ioccur-fontify-buffer-p nil
   "*Fontify `ioccur-current-buffer' when non--nil.
 This allow to have syntactic coloration in `ioccur-buffer' but
 it slow down the start of ioccur at first time on large buffers."

commit b748c263360ce25d6ccd56945ff1aaa225534ddc
Author: Dmitry Gutov <address@hidden>
Date:   Sat Jan 14 00:04:38 2012 +0400

    Skip 'this' nodes when building imenu index (regression)

diff --git a/js2-mode.el b/js2-mode.el
index ab276b5..9b782ee 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6913,11 +6913,13 @@ For instance, processing a nested scope requires a 
parent function node."
   (let (result head fn current-fn parent-qname qname p elem)
     (dolist (entry entries)
       ;; function node goes first
-      (destructuring-bind (current-fn &rest chain) entry
+      (destructuring-bind (current-fn &rest (&whole chain head &rest)) entry
         ;; examine its defining scope;
         ;; if top-level/external, keep as-is
-        (if (js2-node-top-level-decl-p (car chain))
+        (if (js2-node-top-level-decl-p head)
             (push chain result)
+          (when (js2-this-node-p head)
+            (setq chain (cdr chain))) ; discard this-node
           (when (setq fn (js2-node-parent-script-or-fn current-fn))
             (setq parent-qname (gethash fn js2-imenu-function-map 'not-found))
             (when (eq parent-qname 'not-found)

commit 510650bb774f1880cb351a12d2b2d09b729cc220
Merge: 1758a55 b41a828
Author: Dmitry Gutov <address@hidden>
Date:   Fri Jan 13 23:43:40 2012 +0400

    Merge commit 'b41a82' into imenu


commit 1758a550cb6fe57636c078894601281a5c72b1be
Author: Dmitry Gutov <address@hidden>
Date:   Wed Jan 11 21:47:58 2012 +0400

    Play nicer with font-lock
    
    Since this makes the switch to using 'font-lock-face instead of 'face text
    property (so that font-lock doesn't touch it when refontifying), the
    highlighting now depends on font-lock being enabled.
    
    I suppose we could check whether font-lock is enabled at runtime and use 
the one
    or the other property, but really, who would disable font-lock and expect 
the
    syntax highlighting to work?
    
    Refs #32.

diff --git a/js2-mode.el b/js2-mode.el
index 034d195..a3c04b6 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6246,7 +6246,7 @@ corresponding number.  Otherwise return -1."
           end (max (point-min) end))
     (if record
         (push (list beg end face) js2-mode-fontifications)
-      (put-text-property beg end 'face face))))
+      (put-text-property beg end 'font-lock-face face))))
 
 (defsubst js2-set-kid-face (pos kid len face)
   "Set-face on a child node.
@@ -6262,7 +6262,7 @@ FACE is the face to fontify with."
   (js2-set-face start (+ start length) 'font-lock-keyword-face))
 
 (defsubst js2-clear-face (beg end)
-  (remove-text-properties beg end '(face nil
+  (remove-text-properties beg end '(font-lock-face nil
                                     help-echo nil
                                     point-entered nil
                                     c-in-sws nil)))
@@ -10467,18 +10467,10 @@ If so, we don't ever want to use bounce-indent."
 
   ;; We do our own syntax highlighting based on the parse tree.
   ;; However, we want minor modes that add keywords to highlight properly
-  ;; (examples:  doxymacs, column-marker).  We do this by not letting
-  ;; font-lock unfontify anything, and telling it to fontify after we
-  ;; re-parse and re-highlight the buffer.  (We currently don't do any
-  ;; work with regions other than the whole buffer.)
-  (dolist (var '(font-lock-unfontify-buffer-function
-                 font-lock-unfontify-region-function))
-    (set (make-local-variable var) (lambda (&rest args) t)))
-
-  ;; Don't let font-lock do syntactic (string/comment) fontification.
-  (set (make-local-variable #'font-lock-syntactic-face-function)
-       (lambda (state) nil))
-
+  ;; (examples:  doxymacs, column-marker).
+  ;; To customize highlighted keywords, use `font-lock-add-keywords'.
+  (setq font-lock-defaults '(nil t))
+  
   ;; Experiment:  make reparse-delay longer for longer files.
   (if (plusp js2-dynamic-idle-timer-adjust)
       (setq js2-idle-timer-delay
@@ -10571,23 +10563,6 @@ if the edit occurred on a line different from the 
magic paren."
   (js2-mode-hide-overlay)
   (js2-mode-reset-timer))
 
-(defun js2-mode-run-font-lock ()
-  "Run `font-lock-fontify-buffer' after parsing/highlighting.
-This is intended to allow modes that install their own font-lock keywords
-to work with js2-mode.  In practice it never seems to work for long.
-Hopefully the Emacs maintainers can help figure out a way to make it work."
-  (when (and (boundp 'font-lock-keywords)
-             font-lock-keywords
-             (boundp 'font-lock-mode)
-             font-lock-mode)
-    ;; TODO:  font-lock and jit-lock really really REALLY don't want to
-    ;; play nicely with js2-mode.  They go out of their way to fail to
-    ;; provide any option for saying "look, fontify the farging buffer
-    ;; with just the keywords already".  Argh.
-    (setq font-lock-defaults (list font-lock-keywords 'keywords-only))
-    (let (font-lock-verbose)
-      (font-lock-fontify-buffer))))
-
 (defun js2-reparse (&optional force)
   "Re-parse current buffer after user finishes some data entry.
 If we get any user input while parsing, including cursor motion,
@@ -10620,7 +10595,6 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                              (js2-mode-remove-suppressed-warnings)
                              (js2-mode-show-warnings)
                              (js2-mode-show-errors)
-                             (js2-mode-run-font-lock)  ; note:  doesn't work
                              (js2-mode-highlight-magic-parens)
                              (if (>= js2-highlight-level 1)
                                  (js2-highlight-jsdoc js2-mode-ast))
@@ -10650,7 +10624,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
         (if js2-mode-node-overlay
             (move-overlay js2-mode-node-overlay beg end)
           (setq js2-mode-node-overlay (make-overlay beg end))
-          (overlay-put js2-mode-node-overlay 'face 'highlight))
+          (overlay-put js2-mode-node-overlay 'font-lock-face 'highlight))
         (js2-with-unmodifying-text-property-changes
           (put-text-property beg end 'point-left #'js2-mode-hide-overlay))
         (message "%s, parent: %s"
@@ -10691,7 +10665,7 @@ E is a list of ((MSG-KEY MSG-ARG) BEG END)."
          (end (max (point-min) (min end (point-max))))
          (js2-highlight-level 3)    ; so js2-set-face is sure to fire
          (ovl (make-overlay beg end)))
-    (overlay-put ovl 'face face)
+    (overlay-put ovl 'font-lock-face face)
     (overlay-put ovl 'js2-error t)
     (put-text-property beg end 'help-echo (js2-get-msg key))
     (put-text-property beg end 'point-entered #'js2-echo-error)))
@@ -10720,7 +10694,7 @@ Defaults to point."
     ;; Have to reverse the recorded fontifications list so that errors
     ;; and warnings overwrite the normal fontifications.
     (dolist (f (nreverse js2-mode-fontifications))
-      (put-text-property (first f) (second f) 'face (third f)))
+      (put-text-property (first f) (second f) 'font-lock-face (third f)))
     (setq js2-mode-fontifications nil))
   (dolist (p js2-mode-deferred-properties)
     (apply #'put-text-property p))
@@ -10947,7 +10921,7 @@ Actually returns the quote character that begins the 
string."
 Sets value of `js2-magic' text property to line number at POS."
   (propertize delim
               'js2-magic (line-number-at-pos pos)
-              'face 'js2-magic-paren-face))
+              'font-lock-face 'js2-magic-paren-face))
 
 (defun js2-mode-match-delimiter (open close)
   "Insert OPEN (a string) and possibly matching delimiter CLOSE.
@@ -11045,7 +11019,7 @@ already have been inserted."
       (if (get-text-property beg 'js2-magic)
           (js2-with-unmodifying-text-property-changes
             (put-text-property beg (or end (1+ beg))
-                               'face 'js2-magic-paren-face))))))
+                               'font-lock-face 'js2-magic-paren-face))))))
 
 (defun js2-mode-mundanify-parens ()
   "Clear all magic parens and brackets."

commit 04fbc13b5be66bf9876560e3be33dfd486e9fa56
Author: Dmitry Gutov <address@hidden>
Date:   Sun Jan 8 22:55:50 2012 +0400

    Fix 'jumping cursor' problem
    
    Regression from the previous commit.
    Refs #31.

diff --git a/js2-mode.el b/js2-mode.el
index 0b53e27..034d195 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7327,9 +7327,9 @@ leaving a statement, an expression, or a function 
definition."
         (max-specpdl-size (max max-specpdl-size 3000))
         (case-fold-search nil)
         ast)
-    (or buf (setq buf (current-buffer)))
     (message nil)  ; clear any error message from previous parse
-    (with-current-buffer buf
+    (save-excursion
+      (when buf (set-buffer buf))
       (setq js2-scanned-comments nil
             js2-parsed-errors nil
             js2-parsed-warnings nil

commit 5d5a7cce62d847798d407771ae84f63e1a0bd0c1
Author: daimrod <address@hidden>
Date:   Fri Dec 23 18:07:23 2011 +0100

    Use `with-current-buffer` instead of `save-excursion` + `set-buffer`
    
    to fix the deprecation warnings
    
    Closes #28

diff --git a/js2-mode.el b/js2-mode.el
index 3315186..0b53e27 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4512,8 +4512,7 @@ Function also calls `js2-node-add-children' to add the 
parent link."
         pos)
     (unless buf
       (error "No buffer available for node %s" node))
-    (save-excursion
-      (set-buffer buf)
+    (with-current-buffer buf
       (buffer-substring-no-properties (setq pos (js2-node-abs-pos node))
                                       (+ pos (js2-node-len node))))))
 
@@ -7330,8 +7329,7 @@ leaving a statement, an expression, or a function 
definition."
         ast)
     (or buf (setq buf (current-buffer)))
     (message nil)  ; clear any error message from previous parse
-    (save-excursion
-      (set-buffer buf)
+    (with-current-buffer buf
       (setq js2-scanned-comments nil
             js2-parsed-errors nil
             js2-parsed-warnings nil

commit 5805a68e0d32eae42cc5be4e5c3fbe82f3fe059a
Author: Dmitry Gutov <address@hidden>
Date:   Sun Dec 25 19:17:32 2011 +0400

    Eliminate the nasty 'max-lisp-eval-depth' bug during byte-compilation

diff --git a/js2-mode.el b/js2-mode.el
index 9a98720..3315186 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6985,7 +6985,7 @@ For instance, following a 'this' reference requires a 
parent function node."
 ;; a nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
 ;; The sub-alist entries immediately follow INDEX-NAME, the head of the list.
 
-(defsubst js2-treeify (lst)
+(defun js2-treeify (lst)
   "Convert (a b c d) to (a ((b ((c d)))))"
   (if (null (cddr lst))  ; list length <= 2
       lst

commit b41a8289a5d8977c41754f1b5ca548a2bdae35e2
Author: Dmitry Gutov <address@hidden>
Date:   Sun Dec 25 02:41:14 2011 +0400

    Handle unlimited function nesting in imenu index
    
    Refs #27

diff --git a/README.md b/README.md
index 97e6d31..35d3ff5 100644
--- a/README.md
+++ b/README.md
@@ -122,28 +122,24 @@ Proper position for functions in nested object literals:
 Imenu support for function nesting
 ----------------------------------
 
-Supports one level of nesting:
-
-    function foo() {
-        function bar() { // shown as foo.bar
-            function baz() {} // hidden
-        }
-    }
-
-Top-level function can be anonymous wrapper:
+Supports function nesting and anonymous wrappers:
 
     (function() {
-        var foo = function() {}; // shown as foo
-    })();
+      var foo = function() {
+        function bar() { // shown as foo.bar.<definition-1>
+          function baz() {} // foo.bar.baz
+          var qux = function() {}; // foo.bar.quux
+        }
+      };
+    });
 
 Examples of output:
 
-* 
[Underscore.js](https://github.com/documentcloud/underscore/blob/master/underscore.js)
--> <https://gist.github.com/824262>
-* 
[Backbone.js](https://github.com/documentcloud/backbone/blob/master/backbone.js)
--> <https://gist.github.com/824260>
+* [jQuery 1.5](https://gist.github.com/845449)
+* [Underscore.js](https://gist.github.com/824262)
+* [Backbone.js](https://gist.github.com/824260)
 
-No support for library-specific extension methods like _.extend.
+No support for library-specific extension methods like $.extend.
 
 Highlights undeclared/external variables
 ----------------------------------------
diff --git a/js2-mode.el b/js2-mode.el
index 9a98720..ef97b8b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6690,7 +6690,7 @@ it is considered declared."
 ;; possibly other browsing mechanisms.
 
 ;; The basic strategy is to identify function assignment targets of the form
-;; `foo.bar.baz', convert them to (list foo bar baz <position>), and push the
+;; `foo.bar.baz', convert them to (list fn foo bar baz <position>), and push 
the
 ;; list into `js2-imenu-recorder'.  The lists are merged into a trie-like tree
 ;; for imenu after parsing is finished.
 
@@ -6739,13 +6739,14 @@ it is considered declared."
 ;; During parsing we accumulate an entry for each definition in
 ;; the variable `js2-imenu-recorder', like so:
 
-;; '((a 5)
-;;   (b 25)
-;;   (foo 100)
-;;   (foo bar 200)
-;;   (foo bar baz 300)
-;;   (foo bar zab 400))
+;; '((fn a 5)
+;;   (fn b 25)
+;;   (fn foo 100)
+;;   (fn foo bar 200)
+;;   (fn foo bar baz 300)
+;;   (fn foo bar zab 400))
 
+;; Where 'fn' is the respective function node.
 ;; After parsing these entries are merged into this alist-trie:
 
 ;; '((a . 1)
@@ -6775,7 +6776,7 @@ returns nil.  Otherwise returns the string name/value of 
the node."
     "this")))
 
 (defsubst js2-node-qname-component (node)
-  "Test function:  return the name of this node, if it contributes to a qname.
+  "Return the name of this node, if it contributes to a qname.
 Returns nil if the node doesn't contribute."
   (copy-sequence
    (or (js2-prop-node-name node)
@@ -6783,12 +6784,14 @@ Returns nil if the node doesn't contribute."
                 (js2-function-node-name node))
            (js2-name-node-name (js2-function-node-name node))))))
 
-(defsubst js2-record-function-qname (fn-node qname)
-  "Associate FN-NODE with its QNAME for later lookup.
-This is used in postprocessing the chain list.  When we find a chain
-whose first element is a js2-THIS keyword node, we look up the parent
-function and see (using this map) whether it is the tail of a chain.
-If so, we replace the this-node with a copy of the parent's qname."
+(defsubst js2-record-imenu-entry (fn-node qname pos)
+  "Add an entry to `js2-imenu-recorder'.
+FN-NODE should be the current item's function node.
+
+Associate FN-NODE with its QNAME for later lookup.
+This is used in postprocessing the chain list.  For each chain, we find
+the parent function, look up its qname, then prepend a copy of it to the 
chain."
+  (push (cons fn-node (append qname (list pos))) js2-imenu-recorder)
   (unless js2-imenu-function-map
     (setq js2-imenu-function-map (make-hash-table :test 'eq)))
   (puthash fn-node qname js2-imenu-function-map))
@@ -6805,17 +6808,13 @@ VAR, if non-nil, is the expression that NODE is being 
assigned to."
        ((and fun-p
              (not var)
              (setq fname-node (js2-function-node-name node)))
-        (push (setq qname (list fname-node (js2-node-pos node)))
-              js2-imenu-recorder)
-        (js2-record-function-qname node qname))
+        (js2-record-imenu-entry node (list fname-node) (js2-node-pos node)))
        ;; for remaining forms, compute left-side tree branch first
        ((and var (setq qname (js2-compute-nested-prop-get var)))
         (cond
          ;; foo.bar.baz = function
          (fun-p
-          (push (nconc qname (list (js2-node-pos node)))
-                js2-imenu-recorder)
-          (js2-record-function-qname node qname))
+          (js2-record-imenu-entry node qname (js2-node-pos node)))
          ;; foo.bar.baz = object-literal
          ;; look for nested functions:  {a: {b: function() {...} }}
          ((js2-object-node-p node)
@@ -6855,9 +6854,8 @@ NODE is an object literal that is the right-hand child of 
an assignment
 expression.  QNAME is a list of nodes representing the assignment target,
 e.g. for foo.bar.baz = {...}, QNAME is (foo-node bar-node baz-node).
 POS is the absolute position of the node.
-We do a depth-first traversal of NODE.  Any functions we find are prefixed
-with QNAME plus the property name of the function and appended to the
-variable `js2-imenu-recorder'."
+We do a depth-first traversal of NODE.  For any functions we find,
+we append the property name to QNAME, then call `js2-record-imenu-entry'."
   (let (left right prop-qname)
     (dolist (e (js2-object-node-elems node))  ; e is a `js2-object-prop-node'
       (let ((left (js2-infix-node-left e))
@@ -6870,9 +6868,7 @@ variable `js2-imenu-recorder'."
             ;; As a policy decision, we record the position of the property,
             ;; not the position of the `function' keyword, since the property
             ;; is effectively the name of the function.
-            (push (setq prop-qname (append qname (list left pos)))
-                  js2-imenu-recorder)
-            (js2-record-function-qname right prop-qname)))
+            (js2-record-imenu-entry right (append qname (list left)) pos)))
          ;; foo: {object-literal} -- add foo to qname, offset position, and 
recurse
          ((js2-object-node-p right)
           (js2-record-object-literal right
@@ -6911,45 +6907,36 @@ NODE must be `js2-function-node'."
                            '("call" "apply"))
                    (js2-call-node-p (js2-node-parent parent))))))))
 
-(defun js2-browse-postprocess-chains (chains)
+(defun js2-browse-postprocess-chains (entries)
   "Modify function-declaration name chains after parsing finishes.
 Some of the information is only available after the parse tree is complete.
-For instance, following a 'this' reference requires a parent function node."
-  (let ((js2-imenu-fn-type-map (make-hash-table :test 'eq))
-        result head fn fn-type parent-chain p elem parent)
-    (dolist (chain chains)
-      ;; examine the head of each node to get its defining scope
-      (setq head (car chain))
-      ;; if top-level/external, keep as-is
-      (if (js2-node-top-level-decl-p head)
-          (push chain result)
-        (cond
-         ;; starts with this-reference
-         ((js2-this-node-p head)
-          (setq fn (js2-node-parent-script-or-fn head)
-                chain (cdr chain))) ; discard this-node
-         ;; nested named function
-         ((js2-function-node-p (setq parent (js2-node-parent head)))
-          (setq fn (js2-node-parent-script-or-fn parent)))
-         ;; variable assigned a function expression
-         (t (setq fn (js2-node-parent-script-or-fn head))))
-        (when fn
-          (setq fn-type (gethash fn js2-imenu-fn-type-map))
-          (unless fn-type
-            (setq fn-type
-                  (cond ((js2-nested-function-p fn) 'skip)
-                        ((setq parent-chain
-                               (gethash fn js2-imenu-function-map))
-                         'named)
-                        ((js2-wrapper-function-p fn) 'anon)
-                        (t 'skip)))
-            (puthash fn fn-type js2-imenu-fn-type-map))
-          (case fn-type
-            ('anon (push chain result)) ; anonymous top-level wrapper
-            ('named                     ; top-level named function
-             ;; prefix parent fn qname, which is
-             ;; parent-chain sans last elem, to this chain.
-             (push (append (butlast parent-chain) chain) result))))))
+For instance, processing a nested scope requires a parent function node."
+  (let (result head fn current-fn parent-qname qname p elem)
+    (dolist (entry entries)
+      ;; function node goes first
+      (destructuring-bind (current-fn &rest chain) entry
+        ;; examine its defining scope;
+        ;; if top-level/external, keep as-is
+        (if (js2-node-top-level-decl-p (car chain))
+            (push chain result)
+          (when (setq fn (js2-node-parent-script-or-fn current-fn))
+            (setq parent-qname (gethash fn js2-imenu-function-map 'not-found))
+            (when (eq parent-qname 'not-found)
+              ;; anonymous function expressions are not recorded
+              ;; during the parse, so we need to handle this case here
+              (setq parent-qname
+                    (if (js2-wrapper-function-p fn)
+                        (let ((grandparent (js2-node-parent-script-or-fn fn)))
+                          (if (js2-ast-root-p grandparent)
+                              nil
+                            (gethash grandparent js2-imenu-function-map 
'skip)))
+                      'skip))
+              (puthash fn parent-qname js2-imenu-function-map))
+            (unless (eq parent-qname 'skip)
+              ;; prefix parent fn qname to this chain.
+              (let ((qname (append parent-qname chain)))
+                (puthash current-fn (butlast qname) js2-imenu-function-map)
+                (push qname result)))))))
     ;; finally replace each node in each chain with its name.
     (dolist (chain result)
       (setq p chain)

commit 61988bf4eac9cc885283df58b2887e06ce07b43a
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Nov 23 20:30:46 2011 +0100

    Update copyright and headers.

diff --git a/ioccur.el b/ioccur.el
index 39776e9..7b99ff7 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -2,7 +2,7 @@
 
 ;; Author: Thierry Volpiatto <thierry dot volpiatto at gmail dot com>
 
-;; Copyright (C) 2010 Thierry Volpiatto, all rights reserved.
+;; Copyright (C) 2010~2011 Thierry Volpiatto, all rights reserved.
 
 ;; Compatibility: GNU Emacs >=22.3
 
@@ -38,6 +38,15 @@
 
 ;;; Commentary:
 ;;
+;; This package provide similar functionality as occur but is incremental.
+;;
+;; You can jump and quit to an occurence or jump
+;; and save the search buffer (ioccur-buffer) for further use.
+;; It is possible to toggle literal and regexp searching while running.
+;; It is auto documented both in mode-line and tooltip.
+;; It have its own history `ioccur-history' which is a real ring.
+;; etc...
+;;
 ;; To save `ioccur-history', use desktop, adding that to your .emacs:
 ;; (add-to-list 'desktop-globals-to-save 'ioccur-history)
 ;;

commit 83ba8527b39f8ced37843d46336568bf458fd55c
Author: Dmitry Gutov <address@hidden>
Date:   Sun Nov 13 19:01:54 2011 +0400

    Fix indentation of the 2nd line when the 1st line is blank

diff --git a/js2-mode.el b/js2-mode.el
index 17bb8df..9a98720 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9896,10 +9896,12 @@ a comma)."
         (and (js-re-search-backward "\n" nil t)
             (progn
               (skip-chars-backward " \t")
-              (backward-char)
-              (and (js-looking-at-operator-p)
-                   (and (progn (backward-char)
-                               (not (looking-at 
"\\*\\|++\\|--\\|/[/*]"))))))))))
+               (unless (bolp)
+                 (backward-char)
+                 (and (js-looking-at-operator-p)
+                      (and (progn
+                             (backward-char)
+                             (not (looking-at 
"\\*\\|++\\|--\\|/[/*]")))))))))))
 
 (defun js-end-of-do-while-loop-p ()
   "Returns non-nil if word after point is `while' of a do-while

commit 580ad93e26221610e2b871bca1bd6fdd6e87ec2e
Author: Dmitry Gutov <address@hidden>
Date:   Tue Nov 8 11:53:46 2011 +0400

    Don't clobber minibuffer contents with warnings
    
    http://code.google.com/p/js2-mode/issues/detail?id=89
    
    The fix stolen from `help-at-pt-maybe-display`.

diff --git a/js2-mode.el b/js2-mode.el
index 178d7c9..17bb8df 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10769,7 +10769,8 @@ This ensures that the counts and `next-error' are 
correct."
 (defun js2-echo-error (old-point new-point)
   "Called by point-motion hooks."
   (let ((msg (get-text-property new-point 'help-echo)))
-    (if msg
+    (if (and msg (or (not (current-message))
+                     (string= (current-message) "Quit")))
         (message msg))))
 
 (defalias #'js2-echo-help #'js2-echo-error)

commit 504e1e38a8724fc2439f405f0aa8274b58db7b1b
Author: Dmitry Gutov <address@hidden>
Date:   Tue Nov 8 10:12:39 2011 +0400

    Don't mark strict mode decl as having no side effects
    
    Fixes #21

diff --git a/js2-mode.el b/js2-mode.el
index fd2248b..178d7c9 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4829,7 +4829,10 @@ You should use `js2-print-tree' instead of this 
function."
        ;; I'll wait for people to notice incorrect warnings.
        ((and (= tt js2-EXPR_VOID)
              (js2-expr-stmt-node-p node)) ; but not if EXPR_RESULT
-        (js2-node-has-side-effects (js2-expr-stmt-node-expr node)))
+        (let ((expr (js2-expr-stmt-node-expr node)))
+          (or (js2-node-has-side-effects expr)
+              (when (js2-string-node-p expr)
+                (string= "use strict" (js2-string-node-value expr))))))
        ((= tt js2-COMMA)
         (js2-node-has-side-effects (js2-infix-node-right node)))
        ((or (= tt js2-AND)

commit 0e0362b2da54bb5055d61239c4e94366b85c6cf2
Author: Dmitry Gutov <address@hidden>
Date:   Tue Nov 8 08:56:03 2011 +0400

    Run `js2-mode-hook` before doing the first parse
    
    Fixes #20

diff --git a/js2-mode.el b/js2-mode.el
index 09d823b..fd2248b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10491,15 +10491,16 @@ If so, we don't ever want to use bounce-indent."
   (add-to-invisibility-spec '(js2-outline . t))
   (set (make-local-variable 'line-move-ignore-invisible) t)
   (set (make-local-variable 'forward-sexp-function) #'js2-mode-forward-sexp)
+
+  (if (fboundp 'run-mode-hooks)
+      (run-mode-hooks 'js2-mode-hook)
+    (run-hooks 'js2-mode-hook))
+
   (setq js2-mode-functions-hidden nil
         js2-mode-comments-hidden nil
         js2-mode-buffer-dirty-p t
         js2-mode-parsing nil)
-  (js2-reparse)
-
-  (if (fboundp 'run-mode-hooks)
-      (run-mode-hooks 'js2-mode-hook)
-    (run-hooks 'js2-mode-hook)))
+  (js2-reparse))
 
 (defun js2-mode-exit ()
   "Exit `js2-mode' and clean up."

commit 244d4b3d16487f0f6bf1235b343ff4483c0e2983
Author: Chris Wanstrath <address@hidden>
Date:   Mon Oct 31 09:55:32 2011 -0700

    Update version. Fixes #59

diff --git a/coffee-mode.el b/coffee-mode.el
index 15b2336..b93cd32 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010 Chris Wanstrath
 
-;; Version: 0.3.0
+;; Version: 0.4.0
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
 ;; URL: http://github.com/defunkt/coffee-script

commit 080ddacee96436ce274b98da328c1162bf162f71
Merge: 4061f76 62453f2
Author: Dmitry Gutov <address@hidden>
Date:   Thu Oct 27 11:49:11 2011 -0700

    Merge pull request #19 from GunioRobot/clean
    
    Hi! I cleaned up your code for you!


commit 62453f213850685954cac61d9a3f50091ef02d50
Author: Gun.io Whitespace Robot <address@hidden>
Date:   Thu Oct 27 14:05:42 2011 -0400

    Remove whitespace [Gun.io WhitespaceBot]

diff --git a/js2-mode.el b/js2-mode.el
index 8445e30..09d823b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10049,7 +10049,7 @@ In particular, return the buffer position of the first 
`for' kwd."
 
        ((and declaration-indent continued-expr-p)
         (+ declaration-indent js2-basic-offset))
-       
+
        (declaration-indent)
 
        (bracket
@@ -10281,10 +10281,10 @@ in reverse."
 
           ;; nesting-heuristic position, main by default
           (push (setq main-pos normal-col) positions)
-          
+
           ;; delete duplicates and sort positions list
           (setq positions (sort (delete-dups positions) '<))
-          
+
           ;; comma-list continuation lines:  prev line indent takes precedence
           (if same-indent
               (setq main-pos same-indent))
@@ -10297,10 +10297,10 @@ in reverse."
           ;; if bouncing backwards, reverse positions list
           (if backwards
               (setq positions (reverse positions)))
-          
+
           ;; record whether we're already sitting on one of the alternatives
           (setq pos (member cur-indent positions))
-          
+
           (cond
            ;; case 0:  we're one one of the alternatives and this is the
            ;; first time they've pressed TAB on this line (best-guess).
@@ -10322,7 +10322,7 @@ in reverse."
            ;; case 4:  on intermediate position:  cycle to next position
            (t
             (setq computed-pos (js2-position (second pos) positions))))
-          
+
           ;; see if any hooks want to indent; otherwise we do it
           (loop with result = nil
                 for hook in js2-indent-hook
@@ -10332,7 +10332,7 @@ in reverse."
                 finally do
                 (unless (or result (null computed-pos))
                   (indent-line-to (nth computed-pos positions)))))
-      
+
       ;; finally
       (if js2-mode-indent-inhibit-undo
           (setq buffer-undo-list old-buffer-undo-list))

commit c115eb9f3cfcda9d433d13b03ee0dc04278ad405
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Oct 13 22:56:52 2011 +0100

    Normalise strings everywhere

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index ad9e86c..888c803 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -595,7 +595,7 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
         ;; Search forward for a named interface block
         (while (re-search-forward
                 "^[ \t]*interface[ \t]+\\([^ \t\n]+\\)[ \t]*$" nil t)
-          (let* ((name (match-string 1))
+          (let* ((name (f90-normalise-string (match-string 1)))
                  interface)
             (unless (string= name "")
               (setq interface (make-f90-interface :name name))
@@ -679,6 +679,7 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
                     (point)
                     (line-end-position))))
         (mapc (lambda (x)
+                (setq x (f90-normalise-string x))
                 (setf (gethash x (f90-interface-specialisers interface))
                       (make-f90-specialiser :name x)))
               (split-string names "[, \n]+" t))))))
@@ -728,7 +729,7 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
     (goto-char (point-min))
     (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+?\\)[ \t]*$" nil t)
       (error "Trying parse a type but no type found"))
-    (setq type (format "type(%s)" (match-string 1)))
+    (setq type (format "type(%s)" (f90-normalise-string (match-string 1))))
     (while (not (eobp))
       (setq slot (f90-parse-single-type-declaration))
       (when slot
@@ -784,6 +785,7 @@ This works even with derived type subtypes (e.g. if A is a 
type(foo)
 with slot B of type REAL, then A%B is returned being a REAL)."
   (loop for arg in names
         for subspec = nil then nil
+        do (setq arg (f90-normalise-string arg))
         if (string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" arg)
         do (setq subspec (match-string 2 arg)
                  arg (match-string 1 arg))

commit f19ecbcededf1f6d371ff32b938ed1c70dc72421
Merge: a9c8f48 3900a8c
Author: Chris Wanstrath <address@hidden>
Date:   Thu Oct 6 08:22:13 2011 -0700

    Merge pull request #57 from Wilfred/master
    
    add 'undefined' as a reserved word


commit 3900a8c97649c512b2b7e63b86406f6ed3bf4ee9
Author: Wilfred Hughes <address@hidden>
Date:   Thu Oct 6 00:13:19 2011 +0100

    adding undefined to reserved words as part of coffee-boolean-regexp (not a 
proper boolean, but seemed the best fit)

diff --git a/coffee-mode.el b/coffee-mode.el
index 9c6c7fe..15b2336 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -324,7 +324,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
 (defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
 
 ;; Booleans
-(defvar coffee-boolean-regexp 
"\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\)\\b")
+(defvar coffee-boolean-regexp 
"\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\|undefined\\)\\b")
 
 ;; Regular Expressions
 (defvar coffee-regexp-regexp 
"\\/\\(\\\\.\\|\\[\\(\\\\.\\|.\\)+?\\]\\|[^/]\\)+?\\/")

commit a9c8f484e47d2729cea902777cc146c2f3d54697
Author: Scott Barron <address@hidden>
Date:   Thu Sep 29 11:15:15 2011 -0400

    Formatting changes for complians with elp/Marmalade

diff --git a/coffee-mode.el b/coffee-mode.el
index 9503111..9c6c7fe 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010 Chris Wanstrath
 
-;; Version 0.3.0
+;; Version: 0.3.0
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
 ;; URL: http://github.com/defunkt/coffee-script
@@ -727,3 +727,4 @@ line? Returns `t' or `nil'. See the README for more 
details."
 (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
+;;; coffee-mode.el ends here

commit 042838fb0ba16758f60a164048c0b792b3ec3ecd
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Oct 3 09:42:20 2011 +0200

    More robust clang version check.

diff --git a/company-clang.el b/company-clang.el
index 5bd5535..73825f2 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -172,10 +172,12 @@ Prefix files (-include ...) can be selected with
 (defsubst company-clang-version ()
   "Return the version of `company-clang-executable'."
   (with-temp-buffer
+    (switch-to-buffer (current-buffer))
     (call-process company-clang-executable nil t nil "--version")
     (goto-char (point-min))
-    (when (re-search-forward "\\`clang version \\([0-9.]+\\)" nil t)
-      (match-string-no-properties 1))))
+    (if (re-search-forward "\\clang version \\([0-9.]+\\)" nil t)
+        (match-string-no-properties 1)
+      "0")))
 
 (defun company-clang-objc-templatify (selector)
   (let* ((end (point))

commit 7e25b68323adcb46bc43d79924d2008386e5fd0d
Author: Chris Wanstrath <address@hidden>
Date:   Thu Sep 22 12:54:11 2011 -0700

    tweak README spacing example. fixes #53

diff --git a/README.md b/README.md
index 6529124..c7f5834 100644
--- a/README.md
+++ b/README.md
@@ -216,7 +216,8 @@ Naturally. Example:
       "coffee-mode-hook"
 
       ;; CoffeeScript uses two spaces.
-      (set (make-local-variable 'tab-width) 2)
+      (make-local-variable 'tab-width)
+      (set 'tab-width 2)
 
       ;; If you don't have js2-mode
       (setq coffee-js-mode 'javascript-mode)

commit 4061f7601a5ef0329ce5d315f78e077073f0d6c4
Merge: 5666809 ac9a3bf
Author: Masafumi Oyamada <address@hidden>
Date:   Thu Sep 15 23:28:48 2011 -0700

    Merge pull request #17 from db48x/master
    
    better syntax highlighting on jsdoc comments


commit ac9a3bf083cd7af1077463b4ba5c744aa7b98a0f
Author: Daniel Brooks <address@hidden>
Date:   Wed Sep 14 16:17:01 2011 -0700

    make the jsdoc highlighting recoginze optional parameters, which have names 
inside square brackets

diff --git a/js2-mode.el b/js2-mode.el
index eea1b42..8445e30 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6477,7 +6477,7 @@ of a simple name.  Called before EXPR has a parent node."
           "\\(?:param\\|argument\\)"
           "\\)"
           "\\s-*\\({[^}]+}\\)?"         ; optional type
-          "\\s-*\\([a-zA-Z0-9_$]+\\)?"  ; name
+          "\\s-*\\[?\\([a-zA-Z0-9_$]+\\)?\\]?"  ; name
           "\\>")
   "Matches jsdoc tags with optional type and optional param name.")
 

commit 64cf1a9534f7e762c5e7a19d87fde4ae17708dcb
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Sep 13 17:42:29 2011 +0100

    Fix bug in parsing of dimension specifications
    
    A line of the form
    
      type(foo) :: foo(:,:)
    
    would have the type and the modifiers in the wrong order:
    
      ("foo" ("dimension" . 2) "type(foo)")
    
    rather than:
    
      ("foo" "type(foo)" ("dimension" . 2))
    
    Introduce a test to exercise this case and fix it by appending the
    dimension modifier to the type rather than pushing it on the front.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index e4def07..ad9e86c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -880,10 +880,11 @@ dealt with correctly."
                           (setcdr (assoc "dimension" dec)
                                   (1+ (f90-count-commas
                                        (match-string 2 name))))
-                        (push (cons "dimension"
-                                    (1+ (f90-count-commas
-                                         (match-string 2 name))))
-                              dec))
+                        (add-to-list 'dec
+                                     (cons "dimension"
+                                           (1+ (f90-count-commas
+                                                (match-string 2 name))))
+                                     t))
                       (setq name (match-string 1 name)))
             collect (cons name dec)))))
 
diff --git a/f90-tests.el b/f90-tests.el
index 8d996fd..30020b6 100644
--- a/f90-tests.el
+++ b/f90-tests.el
@@ -72,6 +72,8 @@
                                                             ("dimension" . 1))
                                                            ("name2" "integer"
                                                             ("dimension" . 
2))))
+     ((fun "integer, pointer :: name(:, :)") (("name" "integer" "pointer"
+                                               ("dimension" . 2))))
      ((fun "integer, pointer :: NAmE => null()") (("name" "integer" 
"pointer"))))))
 
 

commit 7d80915b235961fdf9a9c4b2e0173aa02cc0f193
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Sep 13 17:41:49 2011 +0100

    Catch errors when evaluating a test form

diff --git a/f90-tests.el b/f90-tests.el
index 185d445..8d996fd 100644
--- a/f90-tests.el
+++ b/f90-tests.el
@@ -17,7 +17,9 @@
   "Run each expression in 'forms' as a test case."
   `(test-combine-results
     ,@(loop for (expr res) in forms
-            collect `(test-report-result (equal ,expr ',res)
+            collect `(test-report-result (equal (condition-case err
+                                                    ,expr
+                                                  (error (gensym))) ',res)
                                          ',expr ',res))))
 
 (defmacro test-combine-results (&rest forms)
@@ -89,4 +91,3 @@
    (test-run-test 'type-modifiers)
    (test-run-test 'parse-declaration)
    (test-run-test 'splits)))
-

commit cdedac13f206e7a12ef3dce36b4bf6307609e306
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Sep 13 17:40:40 2011 +0100

    Populate completion table lazily
    
    Rather than prepopulating the completion table when invoking M-., do
    so lazily when the user asks for a completion candidate.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index dc9e99e..e4def07 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -140,6 +140,17 @@ level.  For example, a LEVEL of 0 counts top-level commas."
     (when fn
       (funcall fn (f90-get-type type)))))
 
+(defun f90-lazy-completion-table ()
+  (lexical-let ((buf (current-buffer)))
+    (lambda (string pred action)
+      (with-current-buffer buf
+        (save-excursion
+          ;; If we need to ask for the tag table, allow that.
+          (let ((enable-recursive-minibuffers t))
+            (visit-tags-table-buffer))
+          (complete-with-action action (f90-merge-into-tags-completion-table 
f90-all-interfaces) string pred))))))
+
+
 (defsubst f90-merge-into-tags-completion-table (ctable)
   "Merge interface completions in CTABLE into `tags-completion-table'."
   (if (or tags-file-name tags-table-list)
@@ -205,8 +216,7 @@ word at point.  For the description of MATCH-SUBLIST see
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Find interface/tag (default %s): " def)
-                        (f90-merge-into-tags-completion-table
-                         f90-all-interfaces)
+                        (f90-lazy-completion-table)
                         nil t nil nil def)
                        current-prefix-arg)))
   (if (f90-valid-interface-name name)

commit a6958aaa7ea3f6d94651ccfe1c4710b05ee19e1f
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Sep 13 17:40:00 2011 +0100

    Set syntax table correctly in f90-arglist-types

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index cd53229..dc9e99e 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -754,17 +754,18 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
            (p (point))
            names)
       (with-temp-buffer
-        (insert str)
-        (goto-char (- p b))
-        (setq p (point-marker))
-        (f90-clean-continuation-lines)
-        (goto-char p)
-        (search-forward "(")
-        (setq names (f90-split-arglist (buffer-substring
-                                        (point)
-                                        (f90-end-of-arglist))))
-        (goto-char (point-min))
-        (f90-arg-types names)))))
+        (with-syntax-table f90-mode-syntax-table
+          (insert str)
+          (goto-char (- p b))
+          (setq p (point-marker))
+          (f90-clean-continuation-lines)
+          (goto-char p)
+          (search-forward "(")
+          (setq names (f90-split-arglist (buffer-substring
+                                          (point)
+                                          (f90-end-of-arglist))))
+          (goto-char (point-min))
+          (f90-arg-types names))))))
 
 (defun f90-arg-types (names)
   "Given NAMES of arguments return their types.

commit b38b24573b8903f643467152ad030ecc1e3d274f
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Sep 13 17:38:51 2011 +0100

    Remove unused function f90-match-arglist-to-specialisers

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 0b67c9c..cd53229 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -494,14 +494,6 @@ default is the type of the variable."
                "; ")))
 
 
-(defun f90-match-arglist-to-specialisers (arglist interface)
-  "Return all matches to ARGLIST in the specialisers of INTERFACE."
-  (let ((specialisers (f90-interface-specialisers interface)))
-    (loop for spec being the hash-values of specialisers
-          when (f90-approx-arglist-match arglist
-                                         (f90-specialiser-arglist spec))
-          collect spec)))
-
 (defun f90-count-non-optional-args (arglist)
   "Count non-optional args in ARGLIST."
   (loop for arg in arglist

commit 2c204efae48ffb866fe0cfb050c19608261efa6b
Author: Koutarou Chikuba <address@hidden>
Date:   Thu Sep 8 15:42:51 2011 +0900

    add coffee-js2coffee-replace-region

diff --git a/coffee-mode.el b/coffee-mode.el
index dac5c20..9503111 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -99,6 +99,13 @@ path."
   :type 'string
   :group 'coffee)
 
+(defcustom js2coffee-command "js2coffee"
+  "The js2coffee command used for evaluating code. Must be in your
+path."
+  :type 'string
+  :group 'coffee)
+
+
 (defcustom coffee-args-repl '("-i")
   "The command line arguments to pass to `coffee-command' to start a REPL."
   :type 'list
@@ -234,6 +241,21 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (funcall coffee-js-mode)
   (goto-char (point-min)))
 
+(defun coffee-js2coffee-replace-region (start end)
+  "Replace JS to coffee in current buffer."
+  (interactive "r")
+
+  (let ((buffer (get-buffer coffee-compiled-buffer-name)))
+    (when buffer
+      (kill-buffer buffer)))
+
+  (call-process-region start end 
+                       js2coffee-command nil
+                       (current-buffer)
+                       )
+  (delete-region start end)
+  )
+
 (defun coffee-show-version ()
   "Prints the `coffee-mode' version."
   (interactive)

commit db880ac4db091bfa45fa992c74af6e44f697cd83
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 9 12:11:06 2011 +0200

    Added tag V-2.3 for changeset 41bfcf9cdc24

commit 5b766ed6fd77e9390a82aee48fa34ec3b1da34cf
Merge: f33709e d2dc9c5
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 9 12:09:43 2011 +0200

    merge default in dev


commit f33709e9e6ca4a6d7ff21ac5abc2917952c17c71
Merge: d2dc9c5 1365480
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 9 12:08:53 2011 +0200

    Merge branchs


commit d2dc9c5d23f2ba79eefdc00b3a87213ac9740e65
Merge: e05e70d 1365480
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 9 09:57:54 2011 +0200

    merge branchs


commit e05e70dbd49c4b84c953ccd7dac75718bd051831
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 9 09:33:54 2011 +0200

    (ioccur-read-search-input): Add C-q command `quoted-insert'.

diff --git a/ioccur.el b/ioccur.el
index aac96e0..39776e9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -806,6 +806,14 @@ START-POINT is the point where we start searching in 
buffer."
                  ((backtab ?\M-n)               ; Next history elm.
                   (start-timer)
                   (cycle-hist 1))
+                 (?\C-q                         ; quoted-insert
+                  (stop-timer)
+                  (let ((char (with-temp-buffer
+                                (call-interactively 'quoted-insert)
+                                (buffer-string))))
+                    (push (string-to-char char) tmp-list))
+                  (start-timer)
+                  t)
                  (t                             ; Store character.
                   (start-timer)
                   (if (characterp char)

commit fde6c898c36dfe00fb1492252b44ce253a569ce3
Merge: c8e7fb7 59cf3ac
Author: Chris Wanstrath <address@hidden>
Date:   Tue Sep 6 12:16:54 2011 -0700

    Merge pull request #48 from lorensr/patch-1
    
    Removed extra parens in example hook.


commit 566680938513f520ec012df5de43e286fe96fd73
Author: Dmitry Gutov <address@hidden>
Date:   Fri Aug 26 00:23:41 2011 +0400

    When don't need to extend the comment, just indent the line
    
    Fixes #14

diff --git a/js2-mode.el b/js2-mode.el
index ec324ba..eea1b42 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10774,7 +10774,8 @@ This ensures that the counts and `next-error' are 
correct."
   "Handle user pressing the Enter key."
   (interactive)
   (let ((parse-status (save-excursion
-                        (syntax-ppss (point)))))
+                        (syntax-ppss (point))))
+        (js2-bounce-indent-p nil))
     (cond
      ;; check if we're inside a string
      ((nth 3 parse-status)
@@ -10785,12 +10786,10 @@ This ensures that the counts and `next-error' are 
correct."
      (t
       ;; should probably figure out what the mode-map says we should do
       (if js2-indent-on-enter-key
-          (let ((js2-bounce-indent-p nil))
-            (js2-indent-line)))
+          (js2-indent-line))
       (insert "\n")
       (if js2-enter-indents-newline
-          (let ((js2-bounce-indent-p nil))
-            (js2-indent-line)))))))
+          (js2-indent-line))))))
 
 (defun js2-mode-split-string (parse-status)
   "Turn a newline in mid-string into a string concatenation.
@@ -10818,7 +10817,7 @@ PARSE-STATUS is as documented in `parse-partial-sexp'."
       (backward-char 1))))
 
 (defun js2-mode-extend-comment ()
-  "When inside a comment block, add comment prefix."
+  "Indent the line and, when inside a comment block, add comment prefix."
   (let (star single col first-line needs-close)
     (save-excursion
       (back-to-indentation)
@@ -10860,12 +10859,15 @@ PARSE-STATUS is as documented in 
`parse-partial-sexp'."
             (insert "\n")
             (indent-to col)
             (insert "*/"))))
-     (single
-      (when (save-excursion
+     ((and single
+           (save-excursion
               (and (zerop (forward-line 1))
-                   (looking-at "\\s-*//")))
-        (indent-to col)
-        (insert "// "))))))
+                   (looking-at "\\s-*//"))))
+      (indent-to col)
+      (insert "// "))
+     ;; don't need to extend the comment after all
+     (js2-enter-indents-newline
+      (js2-indent-line)))))
 
 (defun js2-beginning-of-line ()
   "Toggles point between bol and first non-whitespace char in line.

commit 59cf3ac5065a6ea94eda09207f99488c02963633
Author: Loren Sands-Ramshaw <address@hidden>
Date:   Wed Aug 24 22:56:12 2011 -0300

    Removed extra parens in example hook.

diff --git a/README.md b/README.md
index 1c6968f..6529124 100644
--- a/README.md
+++ b/README.md
@@ -231,14 +231,14 @@ Naturally. Example:
       (define-key coffee-mode-map [(meta r)] 'coffee-compile-buffer)
 
       ;; Riding edge.
-      (setq coffee-command "~/dev/coffee"))
+      (setq coffee-command "~/dev/coffee")
 
       ;; Compile '.coffee' files on every save
       (and (file-exists-p (buffer-file-name))
            (file-exists-p (coffee-compiled-file-name))
-           (coffee-cos-mode t))))
+           (coffee-cos-mode t)))
 
-    (add-hook 'coffee-mode-hook 'coffee-custom))
+    (add-hook 'coffee-mode-hook 'coffee-custom)
 
 ## Configuration
 

commit c8e7fb7cc31ee154b3b381778604ba8e5a0ecce3
Author: Daniel Gregoire <address@hidden>
Date:   Fri Aug 19 11:40:35 2011 -0400

    Use coffee-universal-path for coffee-watch, to properly handle paths across 
platforms

diff --git a/coffee-mode.el b/coffee-mode.el
index 7fdf305..dac5c20 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -258,7 +258,7 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   "Run `coffee-run-cmd' with the --watch flag enabled for a directory or file"
   (interactive "fDirectory or File: ")
   (let ((coffee-compiled-buffer-name coffee-watch-buffer-name)
-        (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(expand-file-name dir-or-file))) " ")))
+        (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(coffee-universal-path dir-or-file))) " ")))
     (coffee-run-cmd args)))
 
 ;;

commit 266849caaa473d56ac737ec6dffc260eb41eee72
Author: Chris Wanstrath <address@hidden>
Date:   Thu Aug 18 22:30:39 2011 -0700

    add apply-partially defun
    
    from http://www.emacswiki.org/emacs/anything-match-plugin.el

diff --git a/coffee-mode.el b/coffee-mode.el
index ae8a309..7fdf305 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -144,6 +144,20 @@ to the error, of course."
   "Keymap for CoffeeScript major mode.")
 
 ;;
+;; Compat
+;;
+
+(unless (fboundp 'apply-partially)
+  (defun apply-partially (fun &rest args)
+    "Return a function that is a partial application of FUN to ARGS.
+ARGS is a list of the first N arguments to pass to FUN.
+The result is a new function which does the same as FUN, except that
+the first N arguments are fixed at the values with which this function
+was called."
+    (lexical-let ((fun fun) (args1 args))
+      (lambda (&rest args2) (apply fun (append args1 args2))))))
+
+;;
 ;; Macros
 ;;
 

commit 7675045cf3f1a995f195ad48937c94241f7d00ff
Author: mooz <address@hidden>
Date:   Wed Aug 17 23:37:11 2011 +0900

    Add notation for byte-compilation. refs #13

diff --git a/README.md b/README.md
index 85e7e7b..97e6d31 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,8 @@ Install
     $ cd js2-mode
     $ emacs --batch -f batch-byte-compile js2-mode.el
 
+_NOTE: Emacs may fail to byte compile js2-mode.el in interactive mode (e.g., 
`M-x byte-compile-file`). Following the above instruction is highly 
recommended. See https://github.com/mooz/js2-mode/issues/13 for details._
+
 Then, place js2-mode.elc into your site-lisp directory.
 
 In you emacs config:

commit 0b06b86d1f153131e1b811eaa784d4fb101096d7
Author: Daniel Gregoire <address@hidden>
Date:   Tue Aug 16 13:53:54 2011 -0700

    Add support for coffee --watch, and in process also add function for 
running coffee with arbitrary arguments within Emacs

diff --git a/coffee-mode.el b/coffee-mode.el
index e7a1712..ae8a309 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -132,6 +132,11 @@ to the error, of course."
   :type 'boolean
   :group 'coffee)
 
+(defcustom coffee-watch-buffer-name "*coffee-watch*"
+  "The name of the scratch buffer used when using the --watch flag with  
CoffeeScript."
+  :type 'string
+  :group 'coffee)
+
 (defvar coffee-mode-hook nil
   "A hook for you to run your own code when the mode is loaded.")
 
@@ -235,6 +240,13 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (interactive)
   (browse-url "http://github.com/defunkt/coffee-mode";))
 
+(defun coffee-watch (dir-or-file)
+  "Run `coffee-run-cmd' with the --watch flag enabled for a directory or file"
+  (interactive "fDirectory or File: ")
+  (let ((coffee-compiled-buffer-name coffee-watch-buffer-name)
+        (args (mapconcat 'identity (append coffee-args-compile (list "--watch" 
(expand-file-name dir-or-file))) " ")))
+    (coffee-run-cmd args)))
+
 ;;
 ;; Menubar
 ;;
@@ -356,6 +368,13 @@ For detail, see `comment-dwim'."
   (let ((full-file-name (coffee-universal-path file-name)))
     (mapconcat 'identity (append (list coffee-command) coffee-args-compile 
(list full-file-name)) " ")))
 
+(defun coffee-run-cmd (args)
+  "Given an arbitrary set of arguments for the `coffee-command', compile the 
command and show output in a custom compilation buffer."
+  (interactive "sArguments: ")
+  (let ((compilation-buffer-name-function (lambda (this-mode)
+                                            (generate-new-buffer-name 
coffee-compiled-buffer-name))))
+    (compile (concat coffee-command " " args))))
+
 ;;
 ;; imenu support
 ;;

commit b4270ded088fef88371904f02a55842fc62363f2
Author: Daniel Gregoire <address@hidden>
Date:   Wed Aug 3 01:27:20 2011 -0400

    Allow existing `coffee-args-compile` to be used for `coffee-compile-region` 
and, by extension, `coffee-compile-buffer`, in addition to its existing use for 
compiling whole files

diff --git a/coffee-mode.el b/coffee-mode.el
index 9970b50..e7a1712 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -207,10 +207,10 @@ If FILENAME is omitted, the current buffer's file name is 
used."
     (when buffer
       (kill-buffer buffer)))
 
-  (call-process-region start end coffee-command nil
-                       (get-buffer-create coffee-compiled-buffer-name)
-                       nil
-                       "-s" "-p" "--bare")
+  (apply (apply-partially 'call-process-region start end coffee-command nil
+                          (get-buffer-create coffee-compiled-buffer-name)
+                          nil)
+         (append coffee-args-compile (list "-s" "-p")))
   (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
   (funcall coffee-js-mode)
   (goto-char (point-min)))

commit 58c1401b287df2f6985926fbaa27e2d56bcd97ec
Merge: 14a0d56 e8fd539
Author: Chris Wanstrath <address@hidden>
Date:   Tue Aug 16 13:51:10 2011 -0700

    Merge pull request #42 from semperos/cygwin-path-support
    
    Add support for Cygwin-style absolute paths on Windows Systems


commit bdf683ec35278f04a8a71bfc27ed8a18dcaabb25
Author: Dmitry Gutov <address@hidden>
Date:   Tue Aug 16 17:29:44 2011 +0400

    Do not warn about trailing commas in destructuring assignment arrays
    
    Fixes http://code.google.com/p/js2-mode/issues/detail?id=110

diff --git a/js2-mode.el b/js2-mode.el
index f94395d..ec324ba 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9427,7 +9427,7 @@ array-literals, array comprehensions and regular 
expressions."
                                       :len (- js2-ts-cursor pos)
                                       :elems (nreverse elems)))
         (apply #'js2-node-add-children pn (js2-array-node-elems pn))
-        (when after-comma
+        (when (and after-comma (not js2-is-in-lhs))
           (js2-parse-warn-trailing-comma "msg.array.trailing.comma"
                                          pos elems after-comma)))
        ;; destructuring binding

commit 14a0d566c6bb909e0b191aec60da61cdb0bb6878
Author: Gergely Risko <address@hidden>
Date:   Sat Aug 13 02:26:10 2011 +0200

    Added coffee-compile-jump-to-error.

diff --git a/README.md b/README.md
index c2ff614..1c6968f 100644
--- a/README.md
+++ b/README.md
@@ -163,6 +163,11 @@ Operating on "basic.coffee" and running this command will 
save a
 "basic.js" in the same directory. Subsequent runs will overwrite the
 file.
 
+If there are compilation errors and we the compiler have returned a
+line number to us for the first error, the point is moved to that
+line, so you can investigate.  If this annoys you, you can set
+`coffee-compile-jump-to-error` to `nil`.
+
 ### coffee-compile-buffer
 
 Compiles the current buffer to JavaScript using the command specified
@@ -293,6 +298,15 @@ The name of the scratch buffer used when compiling 
CoffeeScript.
 
 Default: `"*coffee-compiled*"`
 
+### coffee-compile-jump-to-error
+
+Whether to jump to the first error if compilation fails.  Please note
+that the coffee compiler doesn't always give a line number for the
+issue and in that case it is not possible to jump to the error, of
+course.
+
+Default: `t`
+
 ## Thanks
 
 * Jeremy Ashkenas for CoffeeScript
diff --git a/coffee-mode.el b/coffee-mode.el
index 27a2e6e..97cc245 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -114,6 +114,14 @@ path."
   :type 'string
   :group 'coffee)
 
+(defcustom coffee-compile-jump-to-error t
+  "Whether to jump to the first error if compilation fails.
+Please note that the coffee compiler doesn't always give a line
+number for the issue and in that case it is not possible to jump
+to the error, of course."
+  :type 'boolean
+  :group 'coffee)
+
 (defvar coffee-mode-hook nil
   "A hook for you to run your own code when the mode is loaded.")
 
@@ -167,7 +175,13 @@ If FILENAME is omitted, the current buffer's file name is 
used."
   (let ((compiler-output (shell-command-to-string (coffee-command-compile 
(buffer-file-name)))))
     (if (string= compiler-output "")
         (message "Compiled and saved %s" (coffee-compiled-file-name))
-      (message (car (split-string compiler-output "[\n\r]+"))))))
+      (let* ((msg (car (split-string compiler-output "[\n\r]+")))
+            (line (and (string-match "on line \\([0-9]+\\)" msg)
+                       (string-to-number (match-string 1 msg)))))
+       (message msg)
+       (when (and coffee-compile-jump-to-error line (> line 0))
+         (goto-char (point-min))
+         (forward-line (1- line)))))))
 
 (defun coffee-compile-buffer ()
   "Compiles the current buffer and displays the JS in another buffer."

commit b4b2a5377e92742fc3bc7b748ded86f46f1d62df
Author: Kevin Kelley <address@hidden>
Date:   Sat Aug 13 06:08:33 2011 -0300

    Small patch to fix indentation behavior; before, the global tab-width 
setting is used when inserting tabs with insert-tab, e.g. at the top of 
coffee-newline-and-insert.  I used 'customize-group coffee' to set my 
coffee-tab-width to 2, but I have a global tab width of 4, so the net effect 
was that the number of tabs would be halved every time I hit return.

diff --git a/coffee-mode.el b/coffee-mode.el
index 5162c2a..27a2e6e 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -596,6 +596,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; indentation
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'coffee-indent-line)
+  (set (make-local-variable 'tab-width) coffee-tab-width)
 
   ;; imenu
   (make-local-variable 'imenu-create-index-function)

commit e8fd539ec863e217f0505f81dabbd73cf67b55a9
Author: Daniel Gregoire <address@hidden>
Date:   Fri Aug 5 16:22:30 2011 -0400

    Create function to encapsulate logic of supporting Cygwin-based Windows 
paths, use in coffee-command-compile

diff --git a/coffee-mode.el b/coffee-mode.el
index ee72b66..68e3721 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -329,12 +329,17 @@ For detail, see `comment-dwim'."
   "Given an expanded file name, derive the absolute Cygwin path based on 
`coffee-cygwin-prefix'."
   (replace-regexp-in-string "^[a-zA-Z]:" coffee-cygwin-prefix 
expanded-file-name t))
 
+(defun coffee-universal-path (file-name)
+  "Handle different paths for different OS configurations for CoffeeScript"
+  (let ((full-file-name (expand-file-name file-name)))
+    (if (and (equal system-type 'windows-nt)
+             coffee-cygwin-mode)
+        (coffee-cygwin-path full-file-name)
+      full-file-name)))
+
 (defun coffee-command-compile (file-name)
   "The `coffee-command' with args to compile a file."
-  (let ((full-file-name (if (and (equal system-type 'windows-nt)
-                                 coffee-cygwin-mode)
-                            (coffee-cygwin-path (expand-file-name file-name))
-                         (expand-file-name file-name))))
+  (let ((full-file-name (coffee-universal-path file-name)))
     (mapconcat 'identity (append (list coffee-command) coffee-args-compile 
(list full-file-name)) " ")))
 
 ;;

commit 2d489a8dcd54fd6adfd97d1ea0fd6160768d7a27
Author: Daniel Gregoire <address@hidden>
Date:   Thu Aug 4 23:51:54 2011 -0400

    Add support for Cygwin-style absolute paths, which makes using the file 
compilation feature of CoffeeScript mode possible on Windows systems where 
Node.js is compiled with Cygwin

diff --git a/coffee-mode.el b/coffee-mode.el
index 5162c2a..ee72b66 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -109,6 +109,16 @@ path."
   :type 'list
   :group 'coffee)
 
+(defcustom coffee-cygwin-mode t
+  "For Windows systems, add support for Cygwin-style absolute paths."
+  :type 'boolean
+  :group 'coffee)
+
+(defcustom coffee-cygwin-prefix "/cygdrive/C"
+  "The prefix with which to replace the drive-letter for your Windows 
partition, e.g. 'C:' would be replaced by '/c/cygdrive'."
+  :type 'string
+  :group 'coffee)
+
 (defcustom coffee-compiled-buffer-name "*coffee-compiled*"
   "The name of the scratch buffer used when compiling CoffeeScript."
   :type 'string
@@ -315,9 +325,17 @@ For detail, see `comment-dwim'."
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
+(defun coffee-cygwin-path (expanded-file-name)
+  "Given an expanded file name, derive the absolute Cygwin path based on 
`coffee-cygwin-prefix'."
+  (replace-regexp-in-string "^[a-zA-Z]:" coffee-cygwin-prefix 
expanded-file-name t))
+
 (defun coffee-command-compile (file-name)
   "The `coffee-command' with args to compile a file."
-  (mapconcat 'identity (append (list coffee-command) coffee-args-compile (list 
file-name)) " "))
+  (let ((full-file-name (if (and (equal system-type 'windows-nt)
+                                 coffee-cygwin-mode)
+                            (coffee-cygwin-path (expand-file-name file-name))
+                         (expand-file-name file-name))))
+    (mapconcat 'identity (append (list coffee-command) coffee-args-compile 
(list full-file-name)) " ")))
 
 ;;
 ;; imenu support

commit af89112d78fa3cf0d805a5b2c47e040585f1d838
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 1 07:23:06 2011 +0200

    (ioccur-read-search-input): C-w: Don't yank further than eol.

diff --git a/ioccur.el b/ioccur.el
index 261631f..aac96e0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -791,11 +791,15 @@ START-POINT is the point where we start searching in 
buffer."
                     ;; After a search `ioccur-print-results' have put point
                     ;; to point-max, so reset position.
                     (when yank-point (goto-char yank-point))
-                    (forward-word 1)
-                    (setq initial-input (buffer-substring-no-properties
-                                         yank-point (point)))
-                    (setq yank-point (point))   ; End of last forward-word
-                    (insert-initial-input) t))
+                    (let ((pmax (point-at-eol))
+                          (eoword (save-excursion (forward-word 1) (point))))
+                      ;; Don't yank further than eol.
+                      (unless (> eoword pmax)
+                        (goto-char eoword)
+                        (setq initial-input (buffer-substring-no-properties
+                                             yank-point (point)))
+                        (setq yank-point (point)) ; End of last forward-word
+                        (insert-initial-input)))) t)
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))

commit 1365480ba076593ea45e1a50c74d1af0fec16f3e
Merge: c7f4d2c 9c72a4f
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jul 21 06:45:28 2011 +0200

    Merge branchs.


commit 9c72a4fce3667cb450bfb8f04ab20792547079de
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jul 21 06:40:45 2011 +0200

    Remove one commented line.

diff --git a/ioccur.el b/ioccur.el
index efa2443..261631f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -962,7 +962,6 @@ for commands provided in the `ioccur-buffer'."
                str-no-prop)
           (set-text-properties 0 len nil init-str)
           (setq str-no-prop init-str)
-                                        ;(switch-to-buffer-other-window 
(get-buffer-create ioccur-buffer) t)
           (pop-to-buffer (get-buffer-create ioccur-buffer))
           (ioccur-mode)
           (unwind-protect

commit 27df14a96e460967e4ad6fa3e2147dd97a4959ea
Author: Chris Wanstrath <address@hidden>
Date:   Tue Jul 19 15:29:09 2011 -0700

    Fix coffee-indenters-bol-regexp. Closes #36

diff --git a/coffee-mode.el b/coffee-mode.el
index b1a35f7..5162c2a 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -515,7 +515,7 @@ next line should probably be indented.")
 
 (defun coffee-indenters-bol-regexp ()
   "Builds a regexp out of `coffee-indenters-bol' words."
-  (concat "^" (regexp-opt coffee-indenters-bol 'words)))
+  (regexp-opt coffee-indenters-bol 'words))
 
 (defvar coffee-indenters-eol '(?> ?{ ?\[)
   "Single characters at the end of a line that mean the next line

commit 4631aa18f5f25e1f0e48b29b0233482fa98d70b7
Author: Daniel Brockman <address@hidden>
Date:   Fri Nov 12 10:04:43 2010 +0100

    Use "Coffee" as mode name rather than the idiosynchratic "coffee-mode".

diff --git a/coffee-mode.el b/coffee-mode.el
index f889f5d..b1a35f7 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -570,8 +570,8 @@ line? Returns `t' or `nil'. See the README for more 
details."
 
 ;;;###autoload
 (define-derived-mode coffee-mode fundamental-mode
-  "coffee-mode"
-  "Major mode for editing CoffeeScript..."
+  "Coffee"
+  "Major mode for editing CoffeeScript."
 
   ;; key bindings
   (define-key coffee-mode-map (kbd "A-r") 'coffee-compile-buffer)

commit 4e7b3ab614d18fdbf3d95afcf5e3a982c0bb0d49
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 18 15:52:24 2011 +0100

    New function to parse all files in a tree
    
    Add a new interactive function that prompts for the top of a directory
    tree to recurse into to look for Fortran files to parse.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 1ac9f17..0b67c9c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -32,11 +32,14 @@
 ;; Load this file and tell it to parse all the fortran files in your
 ;; code base.  You can do this one directory at a time by calling
 ;; `f90-parse-interfaces-in-dir' (M-x f90-parse-interfaces-in-dir
-;; RET).  Now you are able to browse (with completion) all defined
-;; interfaces in your code by calling
-;; `f90-browse-interface-specialisers'.  Alternatively, if `point' is
-;; on a function or subroutine call, you can call
-;; `f90-find-tag-interface' and you'll be shown a list of the
+;; RET).  Or you can parse all the fortran files in a directory and
+;; recursively in its subdirectories by calling
+;; `f90-parse-all-interfaces'.
+
+;; Now you are able to browse (with completion) all defined interfaces
+;; in your code by calling `f90-browse-interface-specialisers'.
+;; Alternatively, if `point' is on a function or subroutine call, you
+;; can call `f90-find-tag-interface' and you'll be shown a list of the
 ;; interfaces that match the (possibly typed) argument list of the
 ;; current function.  This latter hooks into the `find-tag' machinery
 ;; so that you can use it on the M-. keybinding and it will fall back
@@ -158,6 +161,32 @@ If NAME matches type(TYPENAME) return TYPENAME, otherwise 
just NAME."
 
 ;;; User-visible routines
 
+(defun f90-parse-all-interfaces (dir)
+  "Parse all interfaces found in DIR and its subdirectories.
+
+Recurse over all directories below DIR and parse interfaces found
+within them using `f90-parse-interfaces-in-dir'."
+  (interactive "DParse files in tree: ")
+  (let (dirs
+       attrs
+        seen
+       (pending (list (expand-file-name dir))))
+    (while pending
+      (push (pop pending) dirs)
+      (let* ((this-dir (car dirs))
+            (contents (directory-files this-dir))
+            (default-directory this-dir))
+       (setq attrs (nthcdr 10 (file-attributes this-dir)))
+       (unless (member attrs seen)
+         (push attrs seen)
+         (dolist (file contents)
+            ;; Ignore hidden directories
+           (and (string-match "\\`[[:alnum:]]" file)
+                (file-directory-p file)
+                 (setq pending (nconc pending
+                                      (list (expand-file-name file)))))))))
+    (mapc 'f90-parse-interfaces-in-dir dirs)))
+
 (defun f90-parse-interfaces-in-dir (dir)
   "Parse all Fortran 90 files in DIR to populate `f90-all-interfaces'."
   (interactive "DParse files in directory: ")

commit a335f6c7165063ac6064bb077052d4b4dacf82be
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 18 15:49:37 2011 +0100

    New variable specifying what file extensions are Fortran 90 code
    
    Rather than hardcoding the regexp for .F90, .f90 and .fpp, add a new
    variable `f90-file-extensions', a list of possible extensions that
    match Fortran 90 files.  While we're at it, add a customisation group
    to pull user options together.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index ce4c2db..1ac9f17 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -72,6 +72,16 @@
   (arglist "")
   location)
 
+(defgroup f90-iface nil
+  "Static parser for Fortran 90 code"
+  :prefix "f90-"
+  :group 'f90)
+
+(defcustom f90-file-extensions (list "f90" "F90" "fpp")
+  "Extensions to consider when looking for Fortran 90 files."
+  :type '(repeat string)
+  :group 'f90-iface)
+
 (defvar f90-interface-type nil)
 (make-variable-buffer-local 'f90-interface-type)
 
@@ -151,7 +161,10 @@ If NAME matches type(TYPENAME) return TYPENAME, otherwise 
just NAME."
 (defun f90-parse-interfaces-in-dir (dir)
   "Parse all Fortran 90 files in DIR to populate `f90-all-interfaces'."
   (interactive "DParse files in directory: ")
-  (loop for file in (directory-files dir t "\\.\\(?:[fF]90\\|fpp\\)\\'")
+  (loop for file in (directory-files dir t
+                                     (rx-to-string
+                                      `(and "." (or ,@f90-file-extensions)
+                                            eos) t))
         do (f90-parse-interfaces file f90-all-interfaces)))
 
 (defun f90-find-tag-interface (name &optional match-sublist)

commit f29d5bef763ebf32ba2199f28c36bfd5234e59a9
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 18 15:47:02 2011 +0100

    Minor optimisation to f90-normalise-string
    
    Separately try and match for whitespace at the beginning and end of
    strings.  This makes the regexp simpler and can speed things up a bit.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 28432ee..ce4c2db 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -509,8 +509,10 @@ first (length ARGLIST) args of SPECIALISER."
   "Return a suitably normalised version of STRING."
   ;; Trim whitespace
   (save-match-data
-    (when (string-match "\\`[ \t]*\\(.+?\\)[ \t]*\\'" string)
-      (setq string (match-string 1 string)))
+    (when (string-match "\\`[ \t]+" string)
+      (setq string (replace-match "" t t string)))
+    (when (string-match "[ \t]+\\'" string)
+      (setq string (replace-match "" t t string)))
     (downcase string)))
 
 (defun f90-get-interface (name &optional interfaces)

commit 534bbdeaf4261b5891f5d45426670dbc5738fbff
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 18 15:46:13 2011 +0100

    Ignore refcount templates when parsing interfaces

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 0b7a85e..28432ee 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -532,7 +532,9 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
       ;; Fiddle things for Fluidity sources
       (when (and (file-exists-p file)
                  (file-readable-p file)
-                 (not (string-match "\\`Reference_count_interface" fname)))
+                 (not (string-match "\\`Reference_count_interface" fname))
+                 (not (string-equal "Refcount_interface_templates.F90" fname))
+                 (not (string-equal "Refcount_templates.F90" fname)))
         (insert-file-contents-literally file)
         (when (string-match "\\`Reference_count_\\([^\\.]+\\)\\.F90" fname)
           (insert-file-contents-literally

commit 340a43798f31661c55325d5a87f075b397388554
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 18 12:03:39 2011 +0100

    Add test framework and some unit tests

diff --git a/f90-tests.el b/f90-tests.el
new file mode 100644
index 0000000..185d445
--- /dev/null
+++ b/f90-tests.el
@@ -0,0 +1,92 @@
+(defvar *test-name* nil)
+
+(defvar *test-tests* (make-hash-table :test 'eq))
+
+(defvar *test-running-tests* nil)
+(defmacro deftest (name parameters &rest body)
+  "Define a test function. Within a test function we can call
+   other test functions or use 'check' to run individual test
+   cases."
+  `(prog1 ',name
+     (setf (gethash ',name *test-tests*)
+           (lambda ,parameters
+             (let ((*test-name* (append *test-name* (list ',name))))
+               ,@body)))))
+
+(defmacro test-check (&rest forms)
+  "Run each expression in 'forms' as a test case."
+  `(test-combine-results
+    ,@(loop for (expr res) in forms
+            collect `(test-report-result (equal ,expr ',res)
+                                         ',expr ',res))))
+
+(defmacro test-combine-results (&rest forms)
+  "Combine the results (as booleans) of evaluating 'forms' in order."
+  (let ((result (make-symbol "result")))
+    `(let ((,result t))
+       ,@(loop for f in forms collect `(unless ,f (setf ,result nil)))
+       ,result)))
+
+(defun test-report-result (result res req)
+  "Report the results of a single test case. Called by 'check'."
+  (if result
+      (insert (format "%s ... %S: %S\n"
+                     (propertize "pass"
+                                 'face '(:weight bold :foreground "green"))
+                     *test-name* res))
+    (insert (format "%s ... %S: %S is not %S\n"
+                   (propertize "FAIL"
+                               'face '(:weight bold :foreground "red"))
+                   *test-name*
+                   res req)))
+  result)
+
+(defun test-run-test (name)
+  (with-current-buffer (get-buffer-create "*test-results*")
+    (unless *test-running-tests*
+      (erase-buffer))
+    (let ((*test-running-tests* t))
+      (funcall (gethash name *test-tests*)))
+    (pop-to-buffer (current-buffer))))
+
+(deftest type-modifiers ()
+  (test-check
+   ((f90-split-declaration "integer") ("integer"))
+   ((f90-split-declaration "integer, pointer") ("integer" "pointer"))
+   ((f90-split-declaration "character(len=*)") ("character"))
+   ((f90-split-declaration "integer, dimension(:)")
+    ("integer" ("dimension" . 1)))))
+
+(deftest parse-declaration ()
+  (flet ((fun (str) (with-temp-buffer
+                      (insert str)
+                      (goto-char (point-min))
+                      (f90-parse-single-type-declaration))))
+    (test-check
+     ((fun "integer :: name") (("name" "integer")))
+     ((fun "integer :: name1, name2") (("name1" "integer")
+                                       ("name2" "integer")))
+     ((fun "integer, dimension(:) :: name1, name2(:, :)") (("name1" "integer"
+                                                            ("dimension" . 1))
+                                                           ("name2" "integer"
+                                                            ("dimension" . 
2))))
+     ((fun "integer, pointer :: NAmE => null()") (("name" "integer" 
"pointer"))))))
+
+
+(deftest splits ()
+  (test-check
+   ((f90-count-commas ",") 1)
+   ((f90-count-commas "(,)") 0)
+   ((f90-count-commas "a, b, size(c, d)") 2)
+   ((f90-count-commas "a, b, size(c, d)" 1) 3)
+   ((f90-split-arglist "a,B") ("a" "b"))
+   ((f90-split-arglist "foo, dimension(1, size(a, b))")
+    ("foo" "dimension(1, size(a, b))"))
+   ((f90-parse-names-list "a=1, B=>null()") ("a" "b"))))
+   
+(deftest all ()
+  (test-combine-results
+   (test-run-test 'type-modifiers)
+   (test-run-test 'parse-declaration)
+   (test-run-test 'splits)))
+

commit d1b583d874f5060028fe33b190608d54e1627d43
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 15 23:07:07 2011 +0100

    Speed up f90-split-arglist
    
    Previously we inserted the arglist into a temporary buffer and split
    it there.  Since we're just using that to loop over the characters in
    the string one at a time, do it in place by looping across the
    characters of the array.  This latter method takes around 70% less
    time than the former.  Since we split arglists thousands of times when
    parsing a source tree, this is a worthwhile optimisation.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 265446f..0b7a85e 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -70,7 +70,7 @@
   (name "" :read-only t)
   (type "")
   (arglist "")
-  (location))
+  location)
 
 (defvar f90-interface-type nil)
 (make-variable-buffer-local 'f90-interface-type)
@@ -772,27 +772,23 @@ For example:
 
   (f90-split-arglist \"foo, bar, baz(quux, zot)\" 1)
     => (\"foo\" \"bar\" \"baz(quux\" \"zot)\")."
-  (let ((cur-level 0)
-        b e ret)
-    (setq level (or level 0))
-    (with-temp-buffer
-      (insert arglist "\n")
-      (goto-char (point-min))
-      (setq b (point))
-      (while (not (eobp))
-        (cond ((eq (char-after) ?\()
-               (incf cur-level))
-              ((eq (char-after) ?\))
-               (decf cur-level))
-              (t nil))
-        (when (and (<= cur-level level)
-                   (or (eq (char-after) ?\,)
-                       (eolp)))
-          (setq e (point))
-          (push (f90-normalise-string (buffer-substring b e)) ret)
-          (setq b (1+ (point))))
-        (forward-char))
-      (nreverse ret))))
+  (setq level (or level 0))
+  (loop for c across arglist
+        for i = 0 then (1+ i)
+        with cur-level = 0
+        with b = 0
+        with len = (length arglist)
+        if (eq c ?\()
+        do (incf cur-level)
+        else if (eq c ?\))
+        do (decf cur-level)
+        if (and (<= cur-level level)
+                (eq c ?,))
+        collect (f90-normalise-string (substring arglist b i))
+        and do (setq b (1+ i))
+        if (and (<= cur-level level)
+                (= (1+ i) len))
+        collect (f90-normalise-string (substring arglist b))))
 
 (defun f90-end-of-arglist ()
   "Find the end of the arglist at `point'."

commit 31eacc5936c63143c6da8e438bd01a8f95cab377
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 15 22:32:31 2011 +0100

    Make dimension parsing more robust
    
    Allow for whitespace in a "dimension(...)" declaration, and move the
    parsing of TYPE :: foo(:) style dimension declarations into
    f90-parse-single-type-declaration, rather than having it in
    f90-make-type-struct.  This way argument matching when looking for
    tags works better.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 38ac689..265446f 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -704,16 +704,6 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
                  (:conc-name ,(make-symbol (format "f90-type.%s." type))))
        (-varnames ',varnames :read-only t)
        ,@(loop for (name . rest) in slots
-               if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
-               do (progn (if (assoc "dimension" (cdr rest))
-                             (setcdr (assoc "dimension" (cdr rest))
-                                     (1+ (f90-count-commas
-                                          (match-string 2 name))))
-                           (push (cons "dimension"
-                                       (1+ (f90-count-commas
-                                            (match-string 2 name))))
-                                 (cdr rest)))
-                         (setq name (match-string 1 name)))
                collect `(,(make-symbol name) (cons ',name ',rest)
                          :read-only t)))))
 
@@ -835,10 +825,22 @@ Assumes that this has the form
 NAMES can optionally have initialisation attached to them which is
 dealt with correctly."
   (when (looking-at "^[ \t]*\\(.*?\\)[ \t]*::[ \t]*\\(.*\\)$")
-    (let ((dec (match-string 1))
+    (let ((dec-orig (match-string 1))
           (names (f90-parse-names-list (match-string 2))))
       (loop for name in names
-            collect (cons name (f90-split-declaration dec))))))
+            for dec = (f90-split-declaration dec-orig)
+            then (f90-split-declaration dec-orig)
+            if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
+            do (progn (if (assoc "dimension" dec)
+                          (setcdr (assoc "dimension" dec)
+                                  (1+ (f90-count-commas
+                                       (match-string 2 name))))
+                        (push (cons "dimension"
+                                    (1+ (f90-count-commas
+                                         (match-string 2 name))))
+                              dec))
+                      (setq name (match-string 1 name)))
+            collect (cons name dec)))))
 
 (defun f90-split-declaration (dec)
   "Split and parse a type declaration DEC.
@@ -848,7 +850,7 @@ and any modifiers."
   (let ((things (f90-split-arglist dec)))
     (cons (car things)
           (loop for thing in (cdr things)
-                if (string-match "dimension(\\(.+\\))" thing)
+                if (string-match "dimension[ \t]*(\\(.+\\))" thing)
                 collect (cons "dimension"
                               (1+ (f90-count-commas (match-string 1 thing))))
                 else if (string-match "character([^)]+)" thing)

commit 0503aa21b23a2e661a928f114a3eb1c69db9d702
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 15 22:29:39 2011 +0100

    Don't stomp on match data when normalising strings
    
    f90-normalise-string needs to look for whitespace, but shouldn't
    destroy the match-data, so wrap the body in save-match-data.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 3a7a445..38ac689 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -508,9 +508,10 @@ first (length ARGLIST) args of SPECIALISER."
 (defun f90-normalise-string (string)
   "Return a suitably normalised version of STRING."
   ;; Trim whitespace
-  (when (string-match "\\`[ \t]*\\(.+?\\)[ \t]*\\'" string)
-    (setq string (match-string 1 string)))
-  (downcase string))
+  (save-match-data
+    (when (string-match "\\`[ \t]*\\(.+?\\)[ \t]*\\'" string)
+      (setq string (match-string 1 string)))
+    (downcase string)))
 
 (defun f90-get-interface (name &optional interfaces)
   "Get the interface with NAME from INTERFACES.

commit 33e00976eed180769a3c2e83fdd5350cc607939f
Author: Lawrence Mitchell <address@hidden>
Date:   Thu Jul 14 16:18:08 2011 +0100

    If no tags are loaded don't try and use tags completion

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index d0c7d63..3a7a445 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -129,12 +129,14 @@ level.  For example, a LEVEL of 0 counts top-level 
commas."
 
 (defsubst f90-merge-into-tags-completion-table (ctable)
   "Merge interface completions in CTABLE into `tags-completion-table'."
-  (let ((table (tags-completion-table)))
-    (maphash (lambda (k v)
-               (ignore v)
-               (intern k table))
-             ctable)
-    table))
+  (if (or tags-file-name tags-table-list)
+      (let ((table (tags-completion-table)))
+        (maphash (lambda (k v)
+                   (ignore v)
+                   (intern k table))
+                 ctable)
+        table)
+    ctable))
 
 (defsubst f90-extract-type-name (name)
   "Return the typename from NAME.

commit dbe92240b61ac62b722c57e27ca23c107666920d
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Jul 12 15:51:46 2011 +0100

    Correctly determine dimension specification
    
    Previously, if we had a dimension spec like dimension(:, max(1, 10))
    we thought the variable had rank 3.  Now we only count top-level
    commas and correctly determine that it is rank 2.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 332c1ac..d0c7d63 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -38,10 +38,16 @@
 ;; on a function or subroutine call, you can call
 ;; `f90-find-tag-interface' and you'll be shown a list of the
 ;; interfaces that match the (possibly typed) argument list of the
-;; current function.
+;; current function.  This latter hooks into the `find-tag' machinery
+;; so that you can use it on the M-. keybinding and it will fall back
+;; to completing tag names if you don't want to look for an interface
+;; definition.
+
 ;; Derived types are also parsed, so that slot types of derived types
 ;; are given the correct type (rather than a UNION-TYPE) when arglist
-;; matching.
+;; matching.  You can show the definition of a know derived type by
+;; calling `f90-show-type-definition' which prompts (with completion)
+;; for a typename to show.
 
 ;; The parsing is by no means complete, it does a half-hearted attempt
 ;; using regular expressions (now you have two problems) rather than
@@ -91,10 +97,12 @@
   "Return non-nil if NAME is an interface name."
   (gethash name f90-all-interfaces))
 
-(defsubst f90-count-commas (str)
-  "Count commas in STR."
-  (loop for c across str
-        count (eq c ?\,)))
+(defsubst f90-count-commas (str &optional level)
+  "Count commas in STR.
+
+If LEVEL is non-nil, only count commas up to the specified nesting
+level.  For example, a LEVEL of 0 counts top-level commas."
+  (1- (length (f90-split-arglist str level))))
 
 (defsubst f90-get-parsed-type-varname (type)
   "Return the variable name of TYPE."
@@ -498,7 +506,7 @@ first (length ARGLIST) args of SPECIALISER."
 (defun f90-normalise-string (string)
   "Return a suitably normalised version of STRING."
   ;; Trim whitespace
-  (when (string-match "\\`[ \t]*\\([^ \t]+\\)[ \t]*\\'" string)
+  (when (string-match "\\`[ \t]*\\(.+?\\)[ \t]*\\'" string)
     (setq string (match-string 1 string)))
   (downcase string))
 
@@ -758,27 +766,33 @@ with slot B of type REAL, then A%B is returned being a 
REAL)."
         (t
          (f90-get-slot-type subspec type))))
 
-(defun f90-split-arglist (arglist)
+(defun f90-split-arglist (arglist &optional level)
   "Split ARGLIST into words.
 
 Split based on top-level commas. e.g.
 
   (f90-split-arglist \"foo, bar, baz(quux, zot)\")
-    => (\"foo\" \"bar\" \"baz(quux, zot)\")."
-  (let ((level 0)
-        b e
-        ret)
+    => (\"foo\" \"bar\" \"baz(quux, zot)\").
+
+If LEVEL is non-nil split on commas up to and including LEVEL.
+For example:
+
+  (f90-split-arglist \"foo, bar, baz(quux, zot)\" 1)
+    => (\"foo\" \"bar\" \"baz(quux\" \"zot)\")."
+  (let ((cur-level 0)
+        b e ret)
+    (setq level (or level 0))
     (with-temp-buffer
       (insert arglist "\n")
       (goto-char (point-min))
       (setq b (point))
       (while (not (eobp))
         (cond ((eq (char-after) ?\()
-               (incf level))
+               (incf cur-level))
               ((eq (char-after) ?\))
-               (decf level))
+               (decf cur-level))
               (t nil))
-        (when (and (zerop level)
+        (when (and (<= cur-level level)
                    (or (eq (char-after) ?\,)
                        (eolp)))
           (setq e (point))
@@ -831,7 +845,7 @@ and any modifiers."
   (let ((things (f90-split-arglist dec)))
     (cons (car things)
           (loop for thing in (cdr things)
-                if (string-match "dimension(\\([^)]+\\))" thing)
+                if (string-match "dimension(\\(.+\\))" thing)
                 collect (cons "dimension"
                               (1+ (f90-count-commas (match-string 1 thing))))
                 else if (string-match "character([^)]+)" thing)

commit 197aaeda8ba0a4e7de0c47487f112869d0195d8e
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Jul 12 15:29:32 2011 +0100

    Default to type-at-point in f90-show-type-definition
    
    Rather than just providing a completion table, try and guess a default
    by looking for a type declaration on the current line, or (if that
    fails) deriving the type of the variable at point.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index de94717..332c1ac 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -128,6 +128,14 @@
              ctable)
     table))
 
+(defsubst f90-extract-type-name (name)
+  "Return the typename from NAME.
+
+If NAME matches type(TYPENAME) return TYPENAME, otherwise just NAME."
+  (if (and name (string-match "\\`type(\\([^)]+\\))\\'" name))
+      (match-string 1 name)
+    name))
+
 ;;; User-visible routines
 
 (defun f90-parse-interfaces-in-dir (dir)
@@ -319,35 +327,76 @@ indicating where we were called from, for jumping back to 
with
 
 ;;; Show type definition
 
+(defun f90-type-at-point ()
+  "Return a guess for the type of the thing at `point'.
+
+If `point' is currently on a line containing a variable declaration,
+return the typename of the declaration.  Otherwise try and figure out
+the typename of the variable at point (possibly including slot
+references)."
+  (let ((name (or
+               ;; Are we on a line with type(TYPENAME)?
+               (save-excursion
+                 (forward-line 0)
+                 (f90-parse-single-type-declaration))
+               ;; No, try and derive the type of the variable at point
+               (save-excursion
+                 (let ((syntax (copy-syntax-table f90-mode-syntax-table)))
+                   (modify-syntax-entry ?% "w" syntax)
+                   (with-syntax-table syntax
+                     (skip-syntax-backward "w")
+                     (f90-arg-types
+                      (list
+                       (buffer-substring-no-properties
+                        (point)
+                        (progn (skip-syntax-forward "w") (point)))))))))))
+    (f90-extract-type-name (f90-get-parsed-type-typename (car name)))))
+
 (defun f90-show-type-definition (type)
   "Show the definition of TYPE.
 
 This formats the parsed definition of TYPE, rather than jumping to the
-existing definition."
-  (interactive (list (completing-read "Type: " f90-types nil t "type(")))
+existing definition.
+
+When called interactively, default to the type of the thing at `point'.
+If `point' is on a type declaration line, the default is the
+declaration type.
+If `point' is on a variable name (possibly with slot references) the
+default is the type of the variable."
+  (interactive (list (let ((def (f90-type-at-point)))
+                       (completing-read
+                        (if def (format "Type (default %s): " def) "Type: ")
+                        (loop for type being the hash-keys of f90-types
+                              collect (f90-extract-type-name type))
+                        nil t nil nil def))))
   (with-current-buffer (get-buffer-create "*Type definition*")
     (setq buffer-read-only nil)
+    (fundamental-mode)
     (erase-buffer)
-    (let* ((type-struct (f90-get-type (list nil type)))
-           (tname (and (string-match "\\`type(\\([^)]+\\))" type)
-                       (match-string 1 type)))
-           (fns (loop for name in (funcall (intern-soft
-                                            (format "f90-type.%s.-varnames"
-                                                    type))
-                                           type-struct)
-                      collect (intern-soft (format "f90-type.%s.%s"
-                                                   type name)))))
-      (insert (format "type %s\n" tname))
-      (loop for fn in fns
-            for parsed = (funcall fn type-struct)
-                then (funcall fn type-struct)
-            do
-            (insert (format "  %s :: %s\n"
-                            (f90-format-parsed-slot-type parsed)
-                            (f90-get-parsed-type-varname parsed))))
-      (insert (format "end type %s\n" tname))
+    (let* ((tname (format "type(%s)" type))
+           (type-struct (f90-get-type (list nil tname)))
+           fns)
+      (when type-struct
+        (setq fns (loop for name in (funcall (intern-soft
+                                              (format "f90-type.%s.-varnames"
+                                                      tname))
+                                             type-struct)
+                        collect (intern-soft (format "f90-type.%s.%s"
+                                                     tname name)))))
+      (if (null type-struct)
+          (insert (format "The type %s is not a known derived type."
+                          type))
+        (insert (format "type %s\n" type))
+        (loop for fn in fns
+              for parsed = (funcall fn type-struct)
+              then (funcall fn type-struct)
+              do
+              (insert (format "  %s :: %s\n"
+                              (f90-format-parsed-slot-type parsed)
+                              (f90-get-parsed-type-varname parsed))))
+        (insert (format "end type %s\n" type))
+        (f90-mode))
       (goto-char (point-min))
-      (f90-mode)
       (view-mode)
       (pop-to-buffer (current-buffer)))))
 

commit 0273b2fa9433cb0d8b8305bef23540c59fe0062e
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Jul 12 13:10:13 2011 +0100

    Speed up f90-clean-comments
    
    Rather than moving through the buffer one character at a time, search
    forward for a possible comment start (a ! character) and then use
    parse-partial-sexp to decide if we're actually in a comment or not.
    
    It turns out most of the time in parsing was actually cleaning
    comments, so this makes the code run significantly faster overall.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 3c5ee4c..de94717 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -434,11 +434,10 @@ first (length ARGLIST) args of SPECIALISER."
   (save-excursion
     (goto-char (point-min))
     (set-syntax-table f90-mode-syntax-table)
-    (while (not (eobp))
+    (while (search-forward "!" nil t)
       (when (nth 4 (parse-partial-sexp (line-beginning-position) (point)))
-        (delete-region (max (1- (point)) (line-beginning-position))
-                       (line-end-position)))
-      (forward-char 1))))
+       (delete-region (max (1- (point)) (line-beginning-position))
+                      (line-end-position))))))
 
 (defun f90-clean-continuation-lines ()
   "Splat Fortran continuation lines in the current buffer onto one line."

commit 716baba1ab1e40b64bd9fada180d408f3216f013
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Jul 12 13:07:31 2011 +0100

    Parse prefix arg through to find-tag from f90-find-tag-interface
    
    If we're searching for a tag, rather than an interface we need to pass
    the prefix arg through so that the find-tag invocation can jump to
    subsequent definitions.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 4a50dfa..3c5ee4c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -153,7 +153,7 @@ word at point.  For the description of MATCH-SUBLIST see
       (f90-browse-interface-specialisers name (f90-arglist-types)
                                          match-sublist
                                          (point-marker))
-    (find-tag name)))
+    (find-tag name match-sublist)))
 
 (defun f90-browse-interface-specialisers (name &optional arglist-to-match
                                                match-sublist

commit 43a6f280e8463e59af8e86d5939490db7d51b6a2
Author: Lawrence Mitchell <address@hidden>
Date:   Tue Jul 12 13:06:24 2011 +0100

    Require etags and cl at runtime
    
    Since we create structs on the fly, we need cl at runtime, not just
    compile time.  We need etags because we push things on to
    find-tag-marker-ring which is not autoloaded.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 3c8a857..4a50dfa 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -50,9 +50,10 @@
 ;;; Code:
 
 ;;; Preamble
-(eval-when-compile (require 'cl))
+(require 'cl)
 (require 'thingatpt)
 (require 'f90)
+(require 'etags)
 
 (defstruct f90-interface
   (name "" :read-only t)

commit 53291f6ea986b0e7096b34d77656930298c124d9
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 17:01:33 2011 +0100

    Document INVOCATION-POINT argument to f90-browse-interface-specialisers

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index eddba41..3c8a857 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -162,7 +162,11 @@ word at point.  For the description of MATCH-SUBLIST see
 If ARGLIST-TO-MATCH is non-nil restrict to those interfaces that match
 it.
 If MATCH-SUBLIST is non-nil only restrict to those interfaces for
-which ARGLIST-TO-MATCH is a sublist of the specialiser's arglist."
+which ARGLIST-TO-MATCH is a sublist of the specialiser's arglist.
+
+If INVOCATION-POINT is non-nil it should be a `point-marker'
+indicating where we were called from, for jumping back to with
+`pop-tag-mark'."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Interface%s: "

commit 9c4a393d7ad42f9ad6bbd11744fba2e160b669a5
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 16:53:46 2011 +0100

    Add more suffixes for likely Fortran files
    
    Rather than just looking for .F90, also look for .f90 and .fpp.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index d3ef9c4..eddba41 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -132,7 +132,7 @@
 (defun f90-parse-interfaces-in-dir (dir)
   "Parse all Fortran 90 files in DIR to populate `f90-all-interfaces'."
   (interactive "DParse files in directory: ")
-  (loop for file in (directory-files dir t "\\.F90\\'")
+  (loop for file in (directory-files dir t "\\.\\(?:[fF]90\\|fpp\\)\\'")
         do (f90-parse-interfaces file f90-all-interfaces)))
 
 (defun f90-find-tag-interface (name &optional match-sublist)

commit d2c2fc53aa11582b9e2be2b6473e16f1b833a6a9
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 16:51:16 2011 +0100

    Fix bug in f90-populate-specialisers
    
    If an interface had multiple "module procedure" lines, we would only
    add the final line to the interface's specialisers.  Fix this by
    initialising the specialisers hash table outside the search loop.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 8202c2a..d3ef9c4 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -560,12 +560,12 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
   "Find all specialisers for INTERFACE."
   (save-excursion
     (goto-char (point-min))
+    (setf (f90-interface-specialisers interface)
+          (make-hash-table :test 'equal))
     (while (search-forward "module procedure" nil t)
       (let ((names (buffer-substring-no-properties
                     (point)
                     (line-end-position))))
-        (setf (f90-interface-specialisers interface)
-              (make-hash-table :test 'equal))
         (mapc (lambda (x)
                 (setf (gethash x (f90-interface-specialisers interface))
                       (make-f90-specialiser :name x)))

commit be9cba7abc177bf408ee43de8196feefa526146b
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 16:48:47 2011 +0100

    Hook into pop-tag-mark machinery when visiting definitions
    
    Make f90-find-definition behave more like find-tag by pushing the
    invocation point onto find-tag-marker-ring when we visit a
    definition.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index e8500c4..8202c2a 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -71,6 +71,9 @@
 (defvar f90-buffer-to-switch-to nil)
 (make-variable-buffer-local 'f90-buffer-to-switch-to)
 
+(defvar f90-invocation-marker nil)
+(make-variable-buffer-local 'f90-invocation-marker)
+
 (defvar f90-all-interfaces (make-hash-table :test 'equal)
   "Hash table populated with all known f90 interfaces.")
 
@@ -121,7 +124,7 @@
     (maphash (lambda (k v)
                (ignore v)
                (intern k table))
-             completion)
+             ctable)
     table))
 
 ;;; User-visible routines
@@ -147,11 +150,13 @@ word at point.  For the description of MATCH-SUBLIST see
                        current-prefix-arg)))
   (if (f90-valid-interface-name name)
       (f90-browse-interface-specialisers name (f90-arglist-types)
-                                         match-sublist)
+                                         match-sublist
+                                         (point-marker))
     (find-tag name)))
 
 (defun f90-browse-interface-specialisers (name &optional arglist-to-match
-                                               match-sublist)
+                                               match-sublist
+                                               invocation-point)
   "Browse all interfaces matching NAME.
 
 If ARGLIST-TO-MATCH is non-nil restrict to those interfaces that match
@@ -167,6 +172,7 @@ which ARGLIST-TO-MATCH is a sublist of the specialiser's 
arglist."
                         f90-all-interfaces
                         nil t nil nil def))))
   (let ((buf (current-buffer)))
+    (or invocation-point (setq invocation-point (point-marker)))
     (with-current-buffer (get-buffer-create "*Interface Browser*")
       (let ((interface (f90-get-interface name f90-all-interfaces))
             (type nil)
@@ -217,6 +223,7 @@ which ARGLIST-TO-MATCH is a sublist of the specialiser's 
arglist."
         (f90-interface-browser-mode)
         (setq f90-buffer-to-switch-to buf)
         (setq f90-interface-type type)
+        (setq f90-invocation-marker invocation-point)
         (pop-to-buffer (current-buffer))))))
 
 (defun f90-next-definition (&optional arg)
@@ -272,7 +279,8 @@ which ARGLIST-TO-MATCH is a sublist of the specialiser's 
arglist."
         (buf (current-buffer))
         buf-to)
     (if location
-        (progn (find-file-other-window (car location))
+        (progn (ring-insert find-tag-marker-ring f90-invocation-marker)
+               (find-file-other-window (car location))
                (setq buf-to (current-buffer))
                (goto-char (cadr location))
                ;; Try forwards then backwards near the recorded

commit b85545886540514bbce23273bbc79fdb509fdc96
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 15:10:13 2011 +0100

    Allow f90-find-tag-interface to complete tags names
    
    When binding f90-find-tag-interface to M-. we want to be able to
    complete tag names (for find-tag) as well as interface names.  So
    merge the tags completion table with the interface name completion
    table.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 75199b7..e8500c4 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -115,6 +115,15 @@
     (when fn
       (funcall fn (f90-get-type type)))))
 
+(defsubst f90-merge-into-tags-completion-table (ctable)
+  "Merge interface completions in CTABLE into `tags-completion-table'."
+  (let ((table (tags-completion-table)))
+    (maphash (lambda (k v)
+               (ignore v)
+               (intern k table))
+             completion)
+    table))
+
 ;;; User-visible routines
 
 (defun f90-parse-interfaces-in-dir (dir)
@@ -131,8 +140,9 @@ word at point.  For the description of MATCH-SUBLIST see
 `f90-browse-interface-specialisers'."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
-                        (format "Interface (default %s): " def)
-                        f90-all-interfaces
+                        (format "Find interface/tag (default %s): " def)
+                        (f90-merge-into-tags-completion-table
+                         f90-all-interfaces)
                         nil t nil nil def)
                        current-prefix-arg)))
   (if (f90-valid-interface-name name)

commit 7816cead2cbaeabce322c486200a855125ef7e4c
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 14:49:25 2011 +0100

    Fix jumping to definitions if we jump past recorded location
    
    In some cases, the cached location of a specialiser might be past the
    definition, in this case we need to search backwards for the beginning
    of the definition if we can't find it looking forwards.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 4686115..75199b7 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -265,8 +265,12 @@ which ARGLIST-TO-MATCH is a sublist of the specialiser's 
arglist."
         (progn (find-file-other-window (car location))
                (setq buf-to (current-buffer))
                (goto-char (cadr location))
-               (re-search-forward (format "%s[ \t]+%s[ \t]*("
-                                          type name) nil t)
+               ;; Try forwards then backwards near the recorded
+               ;; location
+               (or (re-search-forward (format "%s[ \t]+%s[ \t]*("
+                                              type name) nil t)
+                   (re-search-backward (format "%s[ \t]+%s[ \t]*("
+                                               type name) nil t))
                (beginning-of-line)
                (recenter 0)
                (pop-to-buffer buf)
@@ -581,11 +585,12 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
            (format "\\(function\\|subroutine\\)[ \t]+%s[ \t]*("
                    name)
            nil t)
-      (let* ((type (match-string 1))
+      (let* ((point (match-beginning 0))
+             (type (match-string 1))
              (args (f90-split-arglist (buffer-substring-no-properties
                                        (point)
                                        (f90-end-of-arglist)))))
-        (list type (f90-arg-types args) (point))))))
+        (list type (f90-arg-types args) point)))))
 
 (defun f90-parse-type-definition ()
   "Parse a type definition at (or in front of) `point'."

commit 3433074b6a753b0cbe5aad25948df4f05765162f
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 14:35:51 2011 +0100

    Fix f90-get-slot-type for new struct definition

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index a4ac96c..4686115 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -110,7 +110,7 @@
 
 (defsubst f90-get-slot-type (slot type)
   "Get the type of SLOT in TYPE."
-  (let ((fn (intern-soft (format "f90-type.%s-%s"
+  (let ((fn (intern-soft (format "f90-type.%s.%s"
                                  (f90-get-parsed-type-typename type) slot))))
     (when fn
       (funcall fn (f90-get-type type)))))

commit e9c89e347848cb583b29e0ad063c448dbf5c1906
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 12:41:15 2011 +0100

    Fix byte-compilation
    
    Move inlineable functions before their use.  Change
    f90-make-type-struct from a macro to a function (so we can eval its
    result).
    
    In addition, add "-varnames" slot to type structs so we don't have to
    work the entire obarray when we want to show a type definition.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index a8145c4..a4ac96c 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -77,6 +77,44 @@
 (defvar f90-types (make-hash-table :test 'equal)
   "Hash table populated with all known f90 derived types.")
 
+;;; Inlineable utility functions
+
+(defsubst f90-specialisers (name interfaces)
+  "Return all specialisers for NAME in INTERFACES."
+  (f90-interface-specialisers (f90-get-interface name interfaces)))
+
+(defsubst f90-valid-interface-name (name)
+  "Return non-nil if NAME is an interface name."
+  (gethash name f90-all-interfaces))
+
+(defsubst f90-count-commas (str)
+  "Count commas in STR."
+  (loop for c across str
+        count (eq c ?\,)))
+
+(defsubst f90-get-parsed-type-varname (type)
+  "Return the variable name of TYPE."
+  (car type))
+
+(defsubst f90-get-parsed-type-typename (type)
+  "Return the type name of TYPE."
+  (cadr type))
+
+(defsubst f90-get-parsed-type-modifiers (type)
+  "Return the modifiers of TYPE."
+  (cddr type))
+
+(defsubst f90-get-type (type)
+  "Return the struct definition corresponding to TYPE."
+  (gethash (f90-get-parsed-type-typename type) f90-types))
+
+(defsubst f90-get-slot-type (slot type)
+  "Get the type of SLOT in TYPE."
+  (let ((fn (intern-soft (format "f90-type.%s-%s"
+                                 (f90-get-parsed-type-typename type) slot))))
+    (when fn
+      (funcall fn (f90-get-type type)))))
+
 ;;; User-visible routines
 
 (defun f90-parse-interfaces-in-dir (dir)
@@ -263,13 +301,15 @@ existing definition."
   (with-current-buffer (get-buffer-create "*Type definition*")
     (setq buffer-read-only nil)
     (erase-buffer)
-    (let ((type-struct (f90-get-type (list nil type)))
-          (tname (and (string-match "\\`type(\\([^)]+\\))" type)
-                      (match-string 1 type)))
-          (fns (loop for fn being the symbols of obarray
-                     with start = (format "f90-type.%s." type)
-                     when (string-prefix-p start (symbol-name fn))
-                     collect fn)))
+    (let* ((type-struct (f90-get-type (list nil type)))
+           (tname (and (string-match "\\`type(\\([^)]+\\))" type)
+                       (match-string 1 type)))
+           (fns (loop for name in (funcall (intern-soft
+                                            (format "f90-type.%s.-varnames"
+                                                    type))
+                                           type-struct)
+                      collect (intern-soft (format "f90-type.%s.%s"
+                                                   type name)))))
       (insert (format "type %s\n" tname))
       (loop for fn in fns
             for parsed = (funcall fn type-struct)
@@ -282,7 +322,7 @@ existing definition."
       (goto-char (point-min))
       (f90-mode)
       (view-mode)
-      (switch-to-buffer (current-buffer)))))
+      (pop-to-buffer (current-buffer)))))
 
 ;;; Arglist matching/formatting
 
@@ -396,43 +436,6 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
 (defsetf f90-get-interface (name &optional interfaces) (val)
   `(setf (gethash ,name (or ,interfaces f90-all-interfaces)) ,val))
 
-
-(defsubst f90-specialisers (name interfaces)
-  "Return all specialisers for NAME in INTERFACES."
-  (f90-interface-specialisers (f90-get-interface name interfaces)))
-
-(defsubst f90-valid-interface-name (name)
-  "Return non-nil if NAME is an interface name."
-  (gethash name f90-all-interfaces))
-
-(defsubst f90-count-commas (str)
-  "Count commas in STR."
-  (loop for c across str
-        sum (eq c ?\,)))
-
-(defsubst f90-get-parsed-type-varname (type)
-  "Return the variable name of TYPE."
-  (car type))
-
-(defsubst f90-get-parsed-type-typename (type)
-  "Return the type name of TYPE."
-  (cadr type))
-
-(defsubst f90-get-parsed-type-modifiers (type)
-  "Return the modifiers of TYPE."
-  (cddr type))
-
-(defsubst f90-get-type (type)
-  "Return the struct definition corresponding to TYPE."
-  (gethash (f90-get-parsed-type-typename type) f90-types))
-
-(defsubst f90-get-slot-type (slot type)
-  "Get the type of SLOT in TYPE."
-  (let ((fn (intern-soft (format "f90-type.%s-%s"
-                                 (f90-get-parsed-type-typename type) slot))))
-    (when fn
-      (funcall fn (f90-get-type type)))))
-
 ;;; Entry point to parsing routines
 
 (defun f90-parse-interfaces (file existing)
@@ -602,25 +605,30 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
       (error "Something bad went wrong parsing type definition %s" type))
     (setf (gethash type f90-types) (funcall fn))))
 
-(defmacro f90-make-type-struct (type slots)
+(defun f90-make-type-struct (type slots)
   "Create a struct describing TYPE with SLOTS."
-  (let ((struct-name (make-symbol "struct-name")))
-    `(let ((,struct-name (make-symbol (format "f90-type.%s" ,type))))
-       `(defstruct (,,struct-name
-                    (:conc-name ,(make-symbol (format "f90-type.%s." ,type))))
-          ,@(loop for (name . rest) in slots
-                  if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
-                  do (progn (if (assoc "dimension" (cdr rest))
-                                (setcdr (assoc "dimension" (cdr rest))
-                                        (1+ (f90-count-commas
-                                             (match-string 2 name))))
-                              (push (cons "dimension"
-                                          (1+ (f90-count-commas
-                                               (match-string 2 name))))
-                                    (cdr rest)))
-                            (setq name (match-string 1 name)))
-                  collect `(,(make-symbol name) (cons ',name ',rest)
-                            :read-only t))))))
+  (let ((struct-name (make-symbol (format "f90-type.%s" type)))
+        (varnames (reverse (mapcar (lambda (x)
+                                     (setq x (car x))
+                                     (if (string-match "\\([^(]+\\)(" x)
+                                         (match-string 1 x)
+                                       x)) slots))))
+    `(defstruct (,struct-name
+                 (:conc-name ,(make-symbol (format "f90-type.%s." type))))
+       (-varnames ',varnames :read-only t)
+       ,@(loop for (name . rest) in slots
+               if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
+               do (progn (if (assoc "dimension" (cdr rest))
+                             (setcdr (assoc "dimension" (cdr rest))
+                                     (1+ (f90-count-commas
+                                          (match-string 2 name))))
+                           (push (cons "dimension"
+                                       (1+ (f90-count-commas
+                                            (match-string 2 name))))
+                                 (cdr rest)))
+                         (setq name (match-string 1 name)))
+               collect `(,(make-symbol name) (cons ',name ',rest)
+                         :read-only t)))))
 
 (defun f90-arglist-types ()
   "Return the types of the arguments to the function at `point'."

commit 813897e3eebd61998c914deade71cecbaacd7aa0
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 12:05:30 2011 +0100

    Docstring fixes

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 0c6a139..a8145c4 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -327,7 +327,7 @@ existing definition."
 
 
 (defun f90-match-arglist-to-specialisers (arglist interface)
-  "Return all specialisers of INTERFACE matching ARGLIST."
+  "Return all matches to ARGLIST in the specialisers of INTERFACE."
   (let ((specialisers (f90-interface-specialisers interface)))
     (loop for spec being the hash-values of specialisers
           when (f90-approx-arglist-match arglist
@@ -413,9 +413,11 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
 (defsubst f90-get-parsed-type-varname (type)
   "Return the variable name of TYPE."
   (car type))
+
 (defsubst f90-get-parsed-type-typename (type)
   "Return the type name of TYPE."
   (cadr type))
+
 (defsubst f90-get-parsed-type-modifiers (type)
   "Return the modifiers of TYPE."
   (cddr type))

commit fccfb9ee2af9f1ef3b3ec4656895d0ac6a0086ff
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 11:47:18 2011 +0100

    Add function to show the parsed type definition
    
    This allows us to see all the slot names (although without the
    documentation the actual sources have).

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 313e9b1..0c6a139 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -252,6 +252,38 @@ which ARGLIST-TO-MATCH is a sublist of the specialiser's 
arglist."
   (setq buffer-read-only t)
   (set-buffer-modified-p nil))
 
+;;; Show type definition
+
+(defun f90-show-type-definition (type)
+  "Show the definition of TYPE.
+
+This formats the parsed definition of TYPE, rather than jumping to the
+existing definition."
+  (interactive (list (completing-read "Type: " f90-types nil t "type(")))
+  (with-current-buffer (get-buffer-create "*Type definition*")
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (let ((type-struct (f90-get-type (list nil type)))
+          (tname (and (string-match "\\`type(\\([^)]+\\))" type)
+                      (match-string 1 type)))
+          (fns (loop for fn being the symbols of obarray
+                     with start = (format "f90-type.%s." type)
+                     when (string-prefix-p start (symbol-name fn))
+                     collect fn)))
+      (insert (format "type %s\n" tname))
+      (loop for fn in fns
+            for parsed = (funcall fn type-struct)
+                then (funcall fn type-struct)
+            do
+            (insert (format "  %s :: %s\n"
+                            (f90-format-parsed-slot-type parsed)
+                            (f90-get-parsed-type-varname parsed))))
+      (insert (format "end type %s\n" tname))
+      (goto-char (point-min))
+      (f90-mode)
+      (view-mode)
+      (switch-to-buffer (current-buffer)))))
+
 ;;; Arglist matching/formatting
 
 (defun f90-format-parsed-slot-type (type)
@@ -572,7 +604,8 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
   "Create a struct describing TYPE with SLOTS."
   (let ((struct-name (make-symbol "struct-name")))
     `(let ((,struct-name (make-symbol (format "f90-type.%s" ,type))))
-       `(defstruct ,,struct-name
+       `(defstruct (,,struct-name
+                    (:conc-name ,(make-symbol (format "f90-type.%s." ,type))))
           ,@(loop for (name . rest) in slots
                   if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
                   do (progn (if (assoc "dimension" (cdr rest))

commit ed8c0e9f0d681db1f1f25e30e78291ad222588f2
Author: Lawrence Mitchell <address@hidden>
Date:   Mon Jul 11 10:53:16 2011 +0100

    Normalise type-parsing routines and make arglist matching work
    
    We now correctly match types in parsed arglists even in the case of
    slot accesses.  Function calls and array accesses are still not
    handled (we just pass UNION-TYPE through).  But, we do get some more
    specialisation.  For example with some type definitions:
    
     type foo
       type(bar) :: slot
     end type foo
    
     type bar
       real, dimension(:), pointer :: n=>null()
     end type bar
    
    and some code:
    
      type(foo) :: foo
      integer, dimension(10) :: x
    
      call some_function(x%slot, x%slot%n, x(1))
    
    we derive the types of the arguments as:
    
     type(bar); real, dimension(:), pointer; UNION-TYPE
    
    which is significantly better than the previous:
    
     UNION-TYPE; UNION-TYPE; UNION-TYPE

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index c2c43b2..313e9b1 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -39,14 +39,17 @@
 ;; `f90-find-tag-interface' and you'll be shown a list of the
 ;; interfaces that match the (possibly typed) argument list of the
 ;; current function.
+;; Derived types are also parsed, so that slot types of derived types
+;; are given the correct type (rather than a UNION-TYPE) when arglist
+;; matching.
 
 ;; The parsing is by no means complete, it does a half-hearted attempt
 ;; using regular expressions (now you have two problems) rather than
-;; defining a grammar and doing full parsing.  So for instance,
-;; the type of fields of derived subtypes is not known.
+;; defining a grammar and doing full parsing.
 
 ;;; Code:
 
+;;; Preamble
 (eval-when-compile (require 'cl))
 (require 'thingatpt)
 (require 'f90)
@@ -56,7 +59,6 @@
   (publicp nil)
   specialisers)
 
-
 (defstruct f90-specialiser
   (name "" :read-only t)
   (type "")
@@ -69,159 +71,45 @@
 (defvar f90-buffer-to-switch-to nil)
 (make-variable-buffer-local 'f90-buffer-to-switch-to)
 
-(defun f90-clean-continuation-lines ()
-  "Splat Fortran continuation lines in the current buffer onto one line."
-  (save-excursion
-    (goto-char (point-min))
-    (while (re-search-forward "&[ \t]*\n[ \t]*&?" nil t)
-      (replace-match "" nil t))))
-
 (defvar f90-all-interfaces (make-hash-table :test 'equal)
   "Hash table populated with all known f90 interfaces.")
 
 (defvar f90-types (make-hash-table :test 'equal)
   "Hash table populated with all known f90 derived types.")
 
+;;; User-visible routines
+
 (defun f90-parse-interfaces-in-dir (dir)
   "Parse all Fortran 90 files in DIR to populate `f90-all-interfaces'."
   (interactive "DParse files in directory: ")
   (loop for file in (directory-files dir t "\\.F90\\'")
         do (f90-parse-interfaces file f90-all-interfaces)))
 
-(defun f90-get-interface (name &optional interfaces)
-  "Get the interface with NAME from INTERFACES.
-
-If INTERFACES is nil use `f90-all-interfaces' instead."
-  (gethash name (or interfaces f90-all-interfaces)))
-
-(defsetf f90-get-interface (name &optional interfaces) (val)
-  `(setf (gethash ,name (or ,interfaces f90-all-interfaces)) ,val))
-
-(defun f90-parse-interfaces (file existing)
-  "Parse interfaces in FILE and merge into EXISTING interface data."
-  (with-temp-buffer
-    (let ((interfaces (make-hash-table :test 'equal))
-          (fname (file-name-nondirectory file)))
-      (when (and (file-exists-p file)
-                 (file-readable-p file)
-                 (not (string-match "\\`Reference_count_interface" fname)))
-        (insert-file-contents-literally file)
-        (when (string-match "\\`Reference_count_\\([^\\.]+\\)\\.F90" fname)
-          (insert-file-contents-literally
-           (expand-file-name
-            (format "Reference_count_interface_%s.F90"
-                    (match-string 1 fname))
-            (file-name-directory file))))
-        ;; Easier if we don't have to worry about line wrap
-        (f90-clean-comments)
-        (f90-clean-continuation-lines)
-        (goto-char (point-min))
-        ;; Search forward for a named interface block
-        (while (re-search-forward
-                "^[ \t]*interface[ \t]+\\([^ \t\n]+\\)[ \t]*$" nil t)
-          (let* ((name (match-string 1))
-                 interface)
-            (unless (string= name "")
-              (setq interface (make-f90-interface :name name))
-              (save-restriction
-                ;; Figure out all the specialisers for this generic name
-                (narrow-to-region
-                 (point)
-                 (re-search-forward
-                  (format "[ \t]*end interface\\(?:[ \t]+%s\\)?[ \t]*$" name)
-                  nil t))
-                (f90-populate-specialisers interface))
-              ;; Multiple interface blocks with same name (this seems to
-              ;; be allowed).  In which case merge rather than overwrite.
-              (if (f90-get-interface name interfaces)
-                  (f90-merge-interface interface interfaces)
-                (setf (f90-get-interface name interfaces) interface)))))
-        (goto-char (point-min))
-        ;; Parse type definitions
-        (save-excursion
-          (while (re-search-forward
-                  "^[ \t]*type[ \t]+\\(?:[^ \t\n]+\\)[ \t]*$" nil t)
-            (let ((beg (match-beginning 0)))
-              (unless (re-search-forward "^[ \t]*end[ \t]+type.*$" nil t)
-                (error "Unable to find end of type definition"))
-              (save-restriction
-                (narrow-to-region beg (match-beginning 0))
-                (f90-parse-type-definition)))))
-
-        ;; Now find out if an interface is public or private to the module
-        (f90-set-public-attribute interfaces)
-
-        ;; Now find the arglists corresponding to the interface (so we
-        ;; can disambiguate) and record their location in the file.
-        (loop for interface being the hash-values of interfaces
-              do (when (f90-interface-specialisers interface)
-                   (maphash (lambda (specialiser val)
-                              (save-excursion
-                                (goto-char (point-min))
-                                (let ((thing (f90-argument-list specialiser)))
-                                  (setf (f90-specialiser-arglist
-                                         val)
-                                        (cadr thing))
-                                  (setf (f90-specialiser-location
-                                         val)
-                                        (list file (caddr thing)))
-                                  (setf (f90-specialiser-type
-                                         val)
-                                        (car thing)))))
-                            (f90-interface-specialisers interface))))
-        ;; Finally merge these new interfaces into the existing data.
-        (f90-merge-interfaces interfaces existing)))))
-
-(defun f90-merge-interface (interface interfaces)
-  "Merge INTERFACE into the existing set of INTERFACES."
-  (let ((name (f90-interface-name interface))
-        spec-name)
-    (when (f90-interface-specialisers interface)
-      (loop for val being the hash-values of
-            (f90-interface-specialisers interface)
-            do (setq spec-name (f90-specialiser-name val))
-            (setf (gethash spec-name (f90-specialisers name interfaces))
-                  val)))))
-
-(defun f90-merge-interfaces (new existing)
-  "Merge NEW interfaces into EXISTING ones."
-  (maphash (lambda (name val)
-             (if (gethash name existing)
-                 (f90-merge-interface val existing)
-               (setf (gethash name existing)
-                     val)))
-           new))
-
-(defun f90-specialisers (name interfaces)
-  "Return all specialisers for NAME in INTERFACES."
-  (f90-interface-specialisers (f90-get-interface name interfaces)))
-
-(defun f90-valid-interface-name (name)
-  "Return non-nil if NAME is an interface name."
-  (gethash name f90-all-interfaces))
-
-(defun f90-find-tag-interface (name)
+(defun f90-find-tag-interface (name &optional match-sublist)
   "List all interfaces matching NAME.
 
 Restricts list to those matching the (possibly typed) arglist of the
-word at point."
+word at point.  For the description of MATCH-SUBLIST see
+`f90-browse-interface-specialisers'."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Interface (default %s): " def)
                         f90-all-interfaces
-                        nil t nil nil def))))
+                        nil t nil nil def)
+                       current-prefix-arg)))
   (if (f90-valid-interface-name name)
-      (f90-browse-interface-specialisers name (f90-arglist-types))
+      (f90-browse-interface-specialisers name (f90-arglist-types)
+                                         match-sublist)
     (find-tag name)))
 
 (defun f90-browse-interface-specialisers (name &optional arglist-to-match
-                                               first-args-to-match)
+                                               match-sublist)
   "Browse all interfaces matching NAME.
 
 If ARGLIST-TO-MATCH is non-nil restrict to those interfaces that match
 it.
-If FIRST-ARGS-TO-MATCH is non-nil only restrict to those interfaces
-for which the first args match."
+If MATCH-SUBLIST is non-nil only restrict to those interfaces for
+which ARGLIST-TO-MATCH is a sublist of the specialiser's arglist."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Interface%s: "
@@ -241,13 +129,9 @@ for which the first args match."
               (loop for s being the hash-values of
                     (f90-interface-specialisers interface)
                     do (setq type (f90-specialiser-type s))
-                    when (or (and (null arglist-to-match)
-                                  (null first-args-to-match))
+                    when (or (null arglist-to-match)
                              (f90-approx-arglist-match
-                              arglist-to-match s)
-                             (and first-args-to-match
-                                  (f90-approx-arglist-match
-                                   first-args-to-match s t)))
+                              arglist-to-match s match-sublist))
                     do (insert
                         (propertize
                          (concat
@@ -281,44 +165,12 @@ for which the first args match."
                           (if (zerop n-specs)
                               "No interfaces matching arglist (intrinsic?):"
                             "Only showing interfaces matching arglist:")
-                          (f90-format-specialised-arglist arglist-to-match))))
+                          (f90-fontify-arglist arglist-to-match))))
         (f90-interface-browser-mode)
         (setq f90-buffer-to-switch-to buf)
         (setq f90-interface-type type)
         (pop-to-buffer (current-buffer))))))
 
-(defsubst f90-format-parsed-slot-type (type)
-  (if (null type)
-      "UNION-TYPE"
-    (f90-fontify-arglist
-     (list (mapconcat 'identity (loop for a in type
-                                if (and (consp a)
-                                        (string= (car a) "dimension"))
-                                collect (format "dimension(%s)"
-                                                (mapconcat 'identity
-                                                           (make-list (cdr a)
-                                                                      ":")
-                                                           ","))
-                                else
-                                collect a)
-                ", ")))))
-
-(defun f90-format-specialised-arglist (arglist)
-  (mapconcat 'f90-format-parsed-slot-type arglist "; "))
-
-(define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
-  "Major mode for browsing f90 interfaces."
-  (setq buffer-read-only t)
-  (set-buffer-modified-p nil))
-
-(let ((map (make-sparse-keymap)))
-  (define-key map (kbd "RET") 'f90-find-definition)
-  (define-key map (kbd "<down>") 'f90-next-definition)
-  (define-key map (kbd "<up>") 'f90-previous-definition)
-  (define-key map (kbd "q") 'f90-quit-browser)
-  (define-key map (kbd "<mouse-1>") 'f90-mouse-find-definition)
-  (setq f90-interface-browser-mode-map map))
-
 (defun f90-next-definition (&optional arg)
   "Go to the next ARG'th specialiser definition."
   (interactive "p")
@@ -383,12 +235,54 @@ for which the first args match."
                (setq f90-buffer-to-switch-to buf-to))
       (error "No definition at point"))))
 
+(defvar f90-interface-browser-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "RET") 'f90-find-definition)
+    (define-key map (kbd "<down>") 'f90-next-definition)
+    (define-key map (kbd "TAB") 'f90-next-definition)
+    (define-key map (kbd "<up>") 'f90-previous-definition)
+    (define-key map (kbd "<backtab>") 'f90-previous-definition)
+    (define-key map (kbd "q") 'f90-quit-browser)
+    (define-key map (kbd "<mouse-1>") 'f90-mouse-find-definition)
+    map)
+  "Keymap for `f90-interface-browser-mode'.")
+
+(define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
+  "Major mode for browsing f90 interfaces."
+  (setq buffer-read-only t)
+  (set-buffer-modified-p nil))
+
+;;; Arglist matching/formatting
+
+(defun f90-format-parsed-slot-type (type)
+  "Turn a parsed TYPE into a valid f90 type declaration."
+  (if (null type)
+      "UNION-TYPE"
+    ;; Ignore name
+    (setq type (cdr type))
+    (mapconcat 'identity (loop for a in type
+                               if (and (consp a)
+                                       (string= (car a) "dimension"))
+                               collect (format "dimension(%s)"
+                                               (mapconcat 'identity
+                                                          (make-list (cdr a)
+                                                                     ":")
+                                                          ","))
+                               else if (not
+                                        (string-match
+                                         "\\`intent(\\(?:in\\|out\\|inout\\))"
+                                         a))
+                               collect a)
+               ", ")))
+
 (defun f90-fontify-arglist (arglist)
   "Fontify ARGLIST using `f90-mode'."
   (with-temp-buffer
-    (insert (mapconcat (lambda (x)
-                         (format "%s :: foo" (car x)))
-                       arglist "\n"))
+    (if (stringp arglist)
+        (insert (format "%s :: foo\n" arglist))
+      (insert (mapconcat (lambda (x)
+                           (format "%s :: foo" (f90-format-parsed-slot-type 
x)))
+                         arglist "\n")))
     (f90-mode)
     (font-lock-fontify-buffer)
     (goto-char (point-min))
@@ -399,6 +293,225 @@ for which the first args match."
                      do (forward-line 1))
                "; ")))
 
+
+(defun f90-match-arglist-to-specialisers (arglist interface)
+  "Return all specialisers of INTERFACE matching ARGLIST."
+  (let ((specialisers (f90-interface-specialisers interface)))
+    (loop for spec being the hash-values of specialisers
+          when (f90-approx-arglist-match arglist
+                                         (f90-specialiser-arglist spec))
+          collect spec)))
+
+(defun f90-count-non-optional-args (arglist)
+  "Count non-optional args in ARGLIST."
+  (loop for arg in arglist
+        count (not (member "optional" (f90-get-parsed-type-modifiers arg)))))
+
+(defun f90-approx-arglist-match (arglist specialiser &optional match-sub-list)
+  "Return non-nil if ARGLIST matches the arglist of SPECIALISER.
+
+If MATCH-SUB-LIST is non-nil just require that ARGLIST matches the
+first (length ARGLIST) args of SPECIALISER."
+  (let* ((n-passed-args (length arglist))
+         (spec-arglist (f90-specialiser-arglist specialiser))
+         (n-spec-args (length spec-arglist))
+         (n-required-args (f90-count-non-optional-args spec-arglist)))
+    (when (or match-sub-list
+              (and (<= n-required-args n-passed-args)
+                   (<= n-passed-args n-spec-args)))
+      (loop for arg in arglist
+            for spec-arg in spec-arglist
+            with match = nil
+            unless (or (null arg)
+                       (string= (f90-get-parsed-type-typename arg)
+                                (f90-get-parsed-type-typename spec-arg)))
+            do (return nil)
+            finally (return t)))))
+
+;;; Internal functions
+
+(defun f90-clean-comments ()
+  "Clean Fortran 90 comments from the current buffer."
+  (save-excursion
+    (goto-char (point-min))
+    (set-syntax-table f90-mode-syntax-table)
+    (while (not (eobp))
+      (when (nth 4 (parse-partial-sexp (line-beginning-position) (point)))
+        (delete-region (max (1- (point)) (line-beginning-position))
+                       (line-end-position)))
+      (forward-char 1))))
+
+(defun f90-clean-continuation-lines ()
+  "Splat Fortran continuation lines in the current buffer onto one line."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "&[ \t]*\n[ \t]*&?" nil t)
+      (replace-match "" nil t))))
+
+(defun f90-normalise-string (string)
+  "Return a suitably normalised version of STRING."
+  ;; Trim whitespace
+  (when (string-match "\\`[ \t]*\\([^ \t]+\\)[ \t]*\\'" string)
+    (setq string (match-string 1 string)))
+  (downcase string))
+
+(defun f90-get-interface (name &optional interfaces)
+  "Get the interface with NAME from INTERFACES.
+
+If INTERFACES is nil use `f90-all-interfaces' instead."
+  (gethash name (or interfaces f90-all-interfaces)))
+
+(defsetf f90-get-interface (name &optional interfaces) (val)
+  `(setf (gethash ,name (or ,interfaces f90-all-interfaces)) ,val))
+
+
+(defsubst f90-specialisers (name interfaces)
+  "Return all specialisers for NAME in INTERFACES."
+  (f90-interface-specialisers (f90-get-interface name interfaces)))
+
+(defsubst f90-valid-interface-name (name)
+  "Return non-nil if NAME is an interface name."
+  (gethash name f90-all-interfaces))
+
+(defsubst f90-count-commas (str)
+  "Count commas in STR."
+  (loop for c across str
+        sum (eq c ?\,)))
+
+(defsubst f90-get-parsed-type-varname (type)
+  "Return the variable name of TYPE."
+  (car type))
+(defsubst f90-get-parsed-type-typename (type)
+  "Return the type name of TYPE."
+  (cadr type))
+(defsubst f90-get-parsed-type-modifiers (type)
+  "Return the modifiers of TYPE."
+  (cddr type))
+
+(defsubst f90-get-type (type)
+  "Return the struct definition corresponding to TYPE."
+  (gethash (f90-get-parsed-type-typename type) f90-types))
+
+(defsubst f90-get-slot-type (slot type)
+  "Get the type of SLOT in TYPE."
+  (let ((fn (intern-soft (format "f90-type.%s-%s"
+                                 (f90-get-parsed-type-typename type) slot))))
+    (when fn
+      (funcall fn (f90-get-type type)))))
+
+;;; Entry point to parsing routines
+
+(defun f90-parse-interfaces (file existing)
+  "Parse interfaces in FILE and merge into EXISTING interface data."
+  (with-temp-buffer
+    (let ((interfaces (make-hash-table :test 'equal))
+          (fname (file-name-nondirectory file)))
+      ;; Fiddle things for Fluidity sources
+      (when (and (file-exists-p file)
+                 (file-readable-p file)
+                 (not (string-match "\\`Reference_count_interface" fname)))
+        (insert-file-contents-literally file)
+        (when (string-match "\\`Reference_count_\\([^\\.]+\\)\\.F90" fname)
+          (insert-file-contents-literally
+           (expand-file-name
+            (format "Reference_count_interface_%s.F90"
+                    (match-string 1 fname))
+            (file-name-directory file))))
+        ;; Easier if we don't have to worry about line wrap
+        (f90-clean-comments)
+        (f90-clean-continuation-lines)
+        (goto-char (point-min))
+        ;; Search forward for a named interface block
+        (while (re-search-forward
+                "^[ \t]*interface[ \t]+\\([^ \t\n]+\\)[ \t]*$" nil t)
+          (let* ((name (match-string 1))
+                 interface)
+            (unless (string= name "")
+              (setq interface (make-f90-interface :name name))
+              (save-restriction
+                ;; Figure out all the specialisers for this generic name
+                (narrow-to-region
+                 (point)
+                 (re-search-forward
+                  (format "[ \t]*end interface\\(?:[ \t]+%s\\)?[ \t]*$" name)
+                  nil t))
+                (f90-populate-specialisers interface))
+              ;; Multiple interface blocks with same name (this seems to
+              ;; be allowed).  In which case merge rather than overwrite.
+              (if (f90-get-interface name interfaces)
+                  (f90-merge-interface interface interfaces)
+                (setf (f90-get-interface name interfaces) interface)))))
+        (goto-char (point-min))
+        ;; Parse type definitions
+        (save-excursion
+          (while (re-search-forward
+                  "^[ \t]*type[ \t]+\\(?:[^ \t\n]+\\)[ \t]*$" nil t)
+            (let ((beg (match-beginning 0)))
+              (unless (re-search-forward "^[ \t]*end[ \t]+type.*$" nil t)
+                (error "Unable to find end of type definition"))
+              (save-restriction
+                (narrow-to-region beg (match-beginning 0))
+                (f90-parse-type-definition)))))
+
+        ;; Now find out if an interface is public or private to the module
+        (f90-set-public-attribute interfaces)
+
+        ;; Now find the arglists corresponding to the interface (so we
+        ;; can disambiguate) and record their location in the file.
+        (loop for interface being the hash-values of interfaces
+              do (when (f90-interface-specialisers interface)
+                   (maphash (lambda (specialiser val)
+                              (save-excursion
+                                (goto-char (point-min))
+                                (let ((thing (f90-argument-list specialiser)))
+                                  (setf (f90-specialiser-arglist
+                                         val)
+                                        (cadr thing))
+                                  (setf (f90-specialiser-location
+                                         val)
+                                        (list file (caddr thing)))
+                                  (setf (f90-specialiser-type
+                                         val)
+                                        (car thing)))))
+                            (f90-interface-specialisers interface))))
+        ;; Finally merge these new interfaces into the existing data.
+        (f90-merge-interfaces interfaces existing)))))
+
+(defun f90-merge-interface (interface interfaces)
+  "Merge INTERFACE into the existing set of INTERFACES."
+  (let ((name (f90-interface-name interface))
+        spec-name)
+    (when (f90-interface-specialisers interface)
+      (loop for val being the hash-values of
+            (f90-interface-specialisers interface)
+            do (setq spec-name (f90-specialiser-name val))
+            (setf (gethash spec-name (f90-specialisers name interfaces))
+                  val)))))
+
+(defun f90-merge-interfaces (new existing)
+  "Merge NEW interfaces into EXISTING ones."
+  (maphash (lambda (name val)
+             (if (gethash name existing)
+                 (f90-merge-interface val existing)
+               (setf (gethash name existing)
+                     val)))
+           new))
+
+(defun f90-populate-specialisers (interface)
+  "Find all specialisers for INTERFACE."
+  (save-excursion
+    (goto-char (point-min))
+    (while (search-forward "module procedure" nil t)
+      (let ((names (buffer-substring-no-properties
+                    (point)
+                    (line-end-position))))
+        (setf (f90-interface-specialisers interface)
+              (make-hash-table :test 'equal))
+        (mapc (lambda (x)
+                (setf (gethash x (f90-interface-specialisers interface))
+                      (make-f90-specialiser :name x)))
+              (split-string names "[, \n]+" t))))))
+
 (defun f90-set-public-attribute (interfaces)
   "Set public/private flag on all INTERFACES."
   (save-excursion
@@ -423,21 +536,9 @@ for which the first args match."
                       (setf (f90-interface-publicp interface) (not public)))))
                 (split-string names "[, \t]" t)))))))
 
-(defun f90-populate-specialisers (interface)
-  (save-excursion
-    (goto-char (point-min))
-    (while (search-forward "module procedure" nil t)
-      (let ((names (buffer-substring-no-properties
-                    (point)
-                    (line-end-position))))
-        (setf (f90-interface-specialisers interface)
-              (make-hash-table :test 'equal))
-        (mapc (lambda (x)
-                (setf (gethash x (f90-interface-specialisers interface))
-                      (make-f90-specialiser :name x)))
-              (split-string names "[, \n]+" t))))))
-
+;;; Type/arglist parsing
 (defun f90-argument-list (name)
+  "Return typed argument list of function or subroutine NAME."
   (save-excursion
     (when (re-search-forward
            (format "\\(function\\|subroutine\\)[ \t]+%s[ \t]*("
@@ -449,42 +550,45 @@ for which the first args match."
                                        (f90-end-of-arglist)))))
         (list type (f90-arg-types args) (point))))))
 
-(defun f90-arg-types (names)
-  (loop for arg in names
-        for subspec = nil then nil
-        if (string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" arg)
-        do (setq subspec (match-string 2 arg)
-                 arg (match-string 1 arg))
-        collect (save-excursion
-                  (save-restriction
-                    (when (re-search-forward
-                           (format "^[ \t]*\\([^!\n].+?\\)[ \t]*::.*\\<%s\\>"
-                                   arg) nil t)
-                      (let ((type (match-string 1)))
-                        (when (string-match ",[ \t]*intent([^(]+)" type)
-                          (setq type (replace-match "" nil t type)))
-                        (f90-get-type-subtype type subspec)))))))
-
-(defsubst f90-get-type (type)
-  (gethash type f90-types))
-
-(defsubst f90-get-slot-type (slot type)
-  (let ((fn (intern-soft (format "f90-type.%s-%s" type slot))))
-    (when fn
-      (funcall fn (f90-get-type type)))))
+(defun f90-parse-type-definition ()
+  "Parse a type definition at (or in front of) `point'."
+  (let (type slots slot fn)
+    (goto-char (point-min))
+    (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+?\\)[ \t]*$" nil t)
+      (error "Trying parse a type but no type found"))
+    (setq type (format "type(%s)" (match-string 1)))
+    (while (not (eobp))
+      (setq slot (f90-parse-single-type-declaration))
+      (when slot
+        (setf slots (nconc slot slots)))
+      (forward-line 1))
+    (eval (f90-make-type-struct type slots))
+    (setq fn (intern-soft (format "make-f90-type.%s" type)))
+    (unless fn
+      (error "Something bad went wrong parsing type definition %s" type))
+    (setf (gethash type f90-types) (funcall fn))))
 
-(defun f90-get-type-subtype (type subspec)
-  (cond ((null subspec)
-         (list type))
-        ((string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" subspec)
-         (f90-get-type-subtype (car
-                                (f90-get-slot-type (match-string 1 subspec)
-                                                  type))
-                               (match-string 2 subspec)))
-        (t
-         (f90-get-slot-type subspec type))))
+(defmacro f90-make-type-struct (type slots)
+  "Create a struct describing TYPE with SLOTS."
+  (let ((struct-name (make-symbol "struct-name")))
+    `(let ((,struct-name (make-symbol (format "f90-type.%s" ,type))))
+       `(defstruct ,,struct-name
+          ,@(loop for (name . rest) in slots
+                  if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
+                  do (progn (if (assoc "dimension" (cdr rest))
+                                (setcdr (assoc "dimension" (cdr rest))
+                                        (1+ (f90-count-commas
+                                             (match-string 2 name))))
+                              (push (cons "dimension"
+                                          (1+ (f90-count-commas
+                                               (match-string 2 name))))
+                                    (cdr rest)))
+                            (setq name (match-string 1 name)))
+                  collect `(,(make-symbol name) (cons ',name ',rest)
+                            :read-only t))))))
 
 (defun f90-arglist-types ()
+  "Return the types of the arguments to the function at `point'."
   (save-excursion
     (let* ((e (save-excursion (f90-end-of-subprogram) (point)))
            (b (save-excursion (f90-beginning-of-subprogram) (point)))
@@ -504,78 +608,44 @@ for which the first args match."
         (goto-char (point-min))
         (f90-arg-types names)))))
 
-(defun f90-match-arglist-to-specialisers (arglist interface)
-  (let ((specialisers (f90-interface-specialisers interface)))
-    (loop for spec being the hash-values of specialisers
-          when (f90-approx-arglist-match arglist
-                                         (f90-specialiser-arglist spec))
-          collect spec)))
+(defun f90-arg-types (names)
+  "Given NAMES of arguments return their types.
 
-(defun f90-count-non-optional-args (spec-arglist)
-  (loop for arg in spec-arglist
-        count (not (string-match "\\<optional\\>" arg))))
+This works even with derived type subtypes (e.g. if A is a type(foo)
+with slot B of type REAL, then A%B is returned being a REAL)."
+  (loop for arg in names
+        for subspec = nil then nil
+        if (string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" arg)
+        do (setq subspec (match-string 2 arg)
+                 arg (match-string 1 arg))
+        collect (save-excursion
+                  (save-restriction
+                    (when (re-search-forward
+                           (format "^[ \t]*\\([^!\n].+?\\)[ \t]*::.*\\<%s\\>"
+                                   arg) nil t)
+                      (goto-char (match-beginning 0))
+                      (let ((type (assoc arg
+                                         (f90-parse-single-type-declaration))))
+                        (f90-get-type-subtype type subspec)))))))
 
-(defun f90-approx-arglist-match (arglist specialiser &optional match-sub-list)
-  (let* ((n-passed-args (length arglist))
-         (spec-arglist (mapcar 'car (f90-specialiser-arglist specialiser)))
-         (n-spec-args (length spec-arglist))
-         (n-required-args (f90-count-non-optional-args spec-arglist)))
-    (when (or match-sub-list
-              (and (<= n-required-args n-passed-args)
-                   (<= n-passed-args n-spec-args)))
-      (loop for arg in arglist
-            for spec-arg in spec-arglist
-            with match = nil
-            ;; optional arguments can be ignored
-            when (string-match ",[ \t]*optional" spec-arg)
-            do (setq spec-arg (replace-match "" nil t spec-arg))
-            ;; as can targets
-            when (string-match ",[ \t]*target" spec-arg)
-            do (setq spec-arg (replace-match "" nil t spec-arg))
-            if (or (null arg) (f90-match-types arg spec-arg))
-            do (setq match t)
-            else
-            do (return nil)
-            finally (return match)))))
-
-(defun f90-match-types (parsed-type type)
-  ;; Ignore target in type
-  (when (string-match ",[ \t]*target" (car parsed-type))
-    (setf (car parsed-type) (replace-match "" nil t (car parsed-type))))
-  (if (null (cdr parsed-type))
-      (string= (f90-trim-string (car parsed-type)) type)
-    (and (string-match (format "\\`[ \t]*%s"
-                               (f90-trim-string (car parsed-type))) type)
-         (loop for thing in (cdr parsed-type)
-               if (and (consp thing) (string= (car thing) "dimension"))
-               do (unless (and (string-match "dimension[ \t]*(\\([^)]+\\))"
-                                             type)
-                               (= (cdr thing) (1+ (f90-count-commas
-                                                   (match-string 1 type)))))
-                    (return nil))
-               else
-               do (unless (string-match thing type)
-                    (return nil))
-               finally (return t)))))
+(defun f90-get-type-subtype (type subspec)
+  "Return the type of TYPE possibly including slot references in SUBSPEC."
+  (cond ((null subspec)
+         type)
+        ((string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" subspec)
+         (f90-get-type-subtype (f90-get-slot-type (match-string 1 subspec)
+                                                  type)
+                               (match-string 2 subspec)))
+        (t
+         (f90-get-slot-type subspec type))))
 
-(defun f90-end-of-arglist ()
-  (save-excursion
-    (let ((level 0))
-      (while (> level -1)
-        (cond ((eq (char-after) ?\()
-               (incf level))
-              ((eq (char-after) ?\))
-               (decf level))
-              (t nil))
-        (forward-char)))
-    (1- (point))))
+(defun f90-split-arglist (arglist)
+  "Split ARGLIST into words.
 
-(defun f90-trim-string (string)
-  (when (string-match "\\`[ \t]*\\([^ \t]+\\)[ \t]*\\'" string)
-    (setq string (match-string 1 string)))
-  string)
+Split based on top-level commas. e.g.
 
-(defun f90-split-arglist (arglist)
+  (f90-split-arglist \"foo, bar, baz(quux, zot)\")
+    => (\"foo\" \"bar\" \"baz(quux, zot)\")."
   (let ((level 0)
         b e
         ret)
@@ -593,43 +663,52 @@ for which the first args match."
                    (or (eq (char-after) ?\,)
                        (eolp)))
           (setq e (point))
-          (push (f90-trim-string (buffer-substring b e)) ret)
+          (push (f90-normalise-string (buffer-substring b e)) ret)
           (setq b (1+ (point))))
         (forward-char))
       (nreverse ret))))
 
-(defun f90-clean-comments ()
+(defun f90-end-of-arglist ()
+  "Find the end of the arglist at `point'."
   (save-excursion
-    (goto-char (point-min))
-    (set-syntax-table f90-mode-syntax-table)
-    (while (not (eobp))
-      (when (nth 4 (parse-partial-sexp (line-beginning-position) (point)))
-        (delete-region (max (1- (point)) (line-beginning-position))
-                       (line-end-position)))
-      (forward-char 1))))
+    (let ((level 0))
+      (while (> level -1)
+        (cond ((eq (char-after) ?\()
+               (incf level))
+              ((eq (char-after) ?\))
+               (decf level))
+              (t nil))
+        (forward-char)))
+    (1- (point))))
 
 (defun f90-parse-names-list (names)
-  "Return a list of names from the RHS of a :: type declaration."
+  "Return a list of NAMES from the RHS of a :: type declaration."
   (let ((names-list (f90-split-arglist names)))
     (loop for name in names-list
           if (string-match "\\`\\([^=]+\\)[ \t]*=.*\\'" name)
-          collect (f90-trim-string (match-string 1 name))
+          collect (f90-normalise-string (match-string 1 name))
           else
-          collect (f90-trim-string name))))
+          collect (f90-normalise-string name))))
 
 (defun f90-parse-single-type-declaration ()
+  "Parse a single f90 type declaration at `point'.
+
+Assumes that this has the form
+  TYPENAME[, MODIFIERS]* :: NAME[, NAMES]*
+
+NAMES can optionally have initialisation attached to them which is
+dealt with correctly."
   (when (looking-at "^[ \t]*\\(.*?\\)[ \t]*::[ \t]*\\(.*\\)$")
     (let ((dec (match-string 1))
           (names (f90-parse-names-list (match-string 2))))
       (loop for name in names
             collect (cons name (f90-split-declaration dec))))))
 
-(defsubst f90-count-commas (str)
-  (loop for c across str
-        when (eq c ?\,)
-        sum 1))
-
 (defun f90-split-declaration (dec)
+  "Split and parse a type declaration DEC.
+
+This takes the bit before the :: and returns a list of the typename
+and any modifiers."
   (let ((things (f90-split-arglist dec)))
     (cons (car things)
           (loop for thing in (cdr things)
@@ -641,41 +720,6 @@ for which the first args match."
                 else
                 collect thing))))
 
-(defmacro f90-make-type-struct (type slots)
-  (let ((struct-name (make-symbol "struct-name")))
-    `(let ((,struct-name (make-symbol (format "f90-type.%s" ,type))))
-       `(defstruct ,,struct-name
-          ,@(loop for (name . rest) in slots
-                  if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
-                  do (progn (if (assoc "dimension" (cdr rest))
-                                (setcdr (assoc "dimension" (cdr rest))
-                                        (1+ (f90-count-commas
-                                             (match-string 2 name))))
-                              (push (cons "dimension"
-                                          (1+ (f90-count-commas
-                                               (match-string 2 name))))
-                                    (cdr rest)))
-                            (setq name (match-string 1 name)))
-                  collect `(,(make-symbol name) ',rest
-                            :read-only t))))))
-
-(defun f90-parse-type-definition ()
-  (let (type slots slot fn)
-    (goto-char (point-min))
-    (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+?\\)[ \t]*$" nil t)
-      (error "Trying parse a type but no type found"))
-    (setq type (format "type(%s)" (match-string 1)))
-    (while (not (eobp))
-      (setq slot (f90-parse-single-type-declaration))
-      (when slot
-        (setf slots (nconc slot slots)))
-      (forward-line 1))
-    (eval (f90-make-type-struct type slots))
-    (setq fn (intern-soft (format "make-f90-type.%s" type)))
-    (unless fn
-      (error "Something bad went wrong parsing type definition %s" type))
-    (setf (gethash type f90-types) (funcall fn))))
-
 (provide 'f90-interface-browser)
 
 ;;; f90-interface-browser.el ends here

commit 09da94d541aae7c6d1d339f9ada9dce3061f4d34
Author: Lawrence Mitchell <address@hidden>
Date:   Sat Jul 9 22:10:32 2011 +0100

    Further work on type parsing
    
    We're now able to correctly determine argument types that specify
    slots of derived types.  This allows us to be better at specifying
    subsets of the available interfaces.  Needs more work on the approx
    arglist matching code to be really useful.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 098ed3b..c2c43b2 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -79,6 +79,9 @@
 (defvar f90-all-interfaces (make-hash-table :test 'equal)
   "Hash table populated with all known f90 interfaces.")
 
+(defvar f90-types (make-hash-table :test 'equal)
+  "Hash table populated with all known f90 derived types.")
+
 (defun f90-parse-interfaces-in-dir (dir)
   "Parse all Fortran 90 files in DIR to populate `f90-all-interfaces'."
   (interactive "DParse files in directory: ")
@@ -110,28 +113,42 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
                     (match-string 1 fname))
             (file-name-directory file))))
         ;; Easier if we don't have to worry about line wrap
+        (f90-clean-comments)
         (f90-clean-continuation-lines)
         (goto-char (point-min))
         ;; Search forward for a named interface block
-        (while (re-search-forward "^[ \t]*interface[ \t]+\\([^ \t\n]+\\)[ 
\t]*$" nil t)
+        (while (re-search-forward
+                "^[ \t]*interface[ \t]+\\([^ \t\n]+\\)[ \t]*$" nil t)
           (let* ((name (match-string 1))
                  interface)
             (unless (string= name "")
               (setq interface (make-f90-interface :name name))
               (save-restriction
                 ;; Figure out all the specialisers for this generic name
-                (narrow-to-region (point)
-                                  (re-search-forward
-                                   (format "[ \t]*end interface\\(?:[ 
\t]+%s\\)?[ \t]*$"
-                                           name) nil t))
+                (narrow-to-region
+                 (point)
+                 (re-search-forward
+                  (format "[ \t]*end interface\\(?:[ \t]+%s\\)?[ \t]*$" name)
+                  nil t))
                 (f90-populate-specialisers interface))
               ;; Multiple interface blocks with same name (this seems to
               ;; be allowed).  In which case merge rather than overwrite.
               (if (f90-get-interface name interfaces)
                   (f90-merge-interface interface interfaces)
                 (setf (f90-get-interface name interfaces) interface)))))
-        ;; Now find out if an interface is public or private to the module
         (goto-char (point-min))
+        ;; Parse type definitions
+        (save-excursion
+          (while (re-search-forward
+                  "^[ \t]*type[ \t]+\\(?:[^ \t\n]+\\)[ \t]*$" nil t)
+            (let ((beg (match-beginning 0)))
+              (unless (re-search-forward "^[ \t]*end[ \t]+type.*$" nil t)
+                (error "Unable to find end of type definition"))
+              (save-restriction
+                (narrow-to-region beg (match-beginning 0))
+                (f90-parse-type-definition)))))
+
+        ;; Now find out if an interface is public or private to the module
         (f90-set-public-attribute interfaces)
 
         ;; Now find the arglists corresponding to the interface (so we
@@ -194,7 +211,7 @@ word at point."
                         f90-all-interfaces
                         nil t nil nil def))))
   (if (f90-valid-interface-name name)
-      (f90-browse-interface-specialisers name (f90-arglist-types ))
+      (f90-browse-interface-specialisers name (f90-arglist-types))
     (find-tag name)))
 
 (defun f90-browse-interface-specialisers (name &optional arglist-to-match
@@ -216,61 +233,78 @@ for which the first args match."
   (let ((buf (current-buffer)))
     (with-current-buffer (get-buffer-create "*Interface Browser*")
       (let ((interface (f90-get-interface name f90-all-interfaces))
-            (type nil))
+            (type nil)
+            (n-specs 0))
         (setq buffer-read-only nil)
         (erase-buffer)
-        (loop for s being the hash-values of
-              (f90-interface-specialisers interface)
-              when (or (and (null arglist-to-match)
-                            (null first-args-to-match))
-                       (f90-approx-arglist-match
-                        arglist-to-match s)
-                       (and first-args-to-match
-                            (f90-approx-arglist-match
-                             first-args-to-match s t)))
-              do (insert
-                  (propertize
-                   (concat (propertize
-                            (format "%s [defined in %s]\n    (%s)\n"
-                                    (propertize (f90-specialiser-name s)
-                                                'face 'bold)
-                                    (let ((f (car
-                                              (f90-specialiser-location s))))
-                                      (format "%s/%s"
-                                              (file-name-nondirectory
-                                               (directory-file-name
-                                                (file-name-directory f)))
-                                              (file-name-nondirectory f)))
-                                    (f90-fontify-arglist
-                                     (f90-specialiser-arglist s)))
-                            'f90-specialiser-location
-                            (f90-specialiser-location s)
-                            'f90-specialiser-name (f90-specialiser-name s)
-                            'mouse-face 'highlight
-                            'help-echo
-                            "mouse-1: find definition in other window")
-                           "\n")
-                   'f90-specialiser-extent (f90-specialiser-name s)))
-              (setq type (f90-specialiser-type s)))
+        (setq n-specs
+              (loop for s being the hash-values of
+                    (f90-interface-specialisers interface)
+                    do (setq type (f90-specialiser-type s))
+                    when (or (and (null arglist-to-match)
+                                  (null first-args-to-match))
+                             (f90-approx-arglist-match
+                              arglist-to-match s)
+                             (and first-args-to-match
+                                  (f90-approx-arglist-match
+                                   first-args-to-match s t)))
+                    do (insert
+                        (propertize
+                         (concat
+                          (propertize
+                           (format "%s [defined in %s]\n    (%s)\n"
+                                   (propertize (f90-specialiser-name s)
+                                               'face 'bold)
+                                   (let ((f (car
+                                             (f90-specialiser-location s))))
+                                     (format "%s/%s"
+                                             (file-name-nondirectory
+                                              (directory-file-name
+                                               (file-name-directory f)))
+                                             (file-name-nondirectory f)))
+                                   (f90-fontify-arglist
+                                    (f90-specialiser-arglist s)))
+                           'f90-specialiser-location
+                           (f90-specialiser-location s)
+                           'f90-specialiser-name (f90-specialiser-name s)
+                           'mouse-face 'highlight
+                           'help-echo
+                           "mouse-1: find definition in other window")
+                          "\n")
+                         'f90-specialiser-extent (f90-specialiser-name s)))
+                    and count 1))
         (goto-char (point-min))
-        (insert (format "Interfaces for %s%s %s:\n\n"
-                        (if (f90-interface-publicp interface)
-                            ""
-                          "private ")
-                        type (f90-interface-name interface)))
+        (insert (format "Interfaces for %s:\n\n"
+                        (f90-interface-name interface)))
         (when arglist-to-match
-          (insert (format "Only showing interfaces matching arglist:\n%s\n\n"
+          (insert (format "%s\n%s\n\n"
+                          (if (zerop n-specs)
+                              "No interfaces matching arglist (intrinsic?):"
+                            "Only showing interfaces matching arglist:")
                           (f90-format-specialised-arglist arglist-to-match))))
         (f90-interface-browser-mode)
         (setq f90-buffer-to-switch-to buf)
         (setq f90-interface-type type)
         (pop-to-buffer (current-buffer))))))
 
+(defsubst f90-format-parsed-slot-type (type)
+  (if (null type)
+      "UNION-TYPE"
+    (f90-fontify-arglist
+     (list (mapconcat 'identity (loop for a in type
+                                if (and (consp a)
+                                        (string= (car a) "dimension"))
+                                collect (format "dimension(%s)"
+                                                (mapconcat 'identity
+                                                           (make-list (cdr a)
+                                                                      ":")
+                                                           ","))
+                                else
+                                collect a)
+                ", ")))))
+
 (defun f90-format-specialised-arglist (arglist)
-  (mapconcat (lambda (x)
-               (or x "UNION-TYPE"))
-             arglist
-             "; "))
+  (mapconcat 'f90-format-parsed-slot-type arglist "; "))
 
 (define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
   "Major mode for browsing f90 interfaces."
@@ -353,7 +387,7 @@ for which the first args match."
   "Fontify ARGLIST using `f90-mode'."
   (with-temp-buffer
     (insert (mapconcat (lambda (x)
-                         (format "%s :: foo" x))
+                         (format "%s :: foo" (car x)))
                        arglist "\n"))
     (f90-mode)
     (font-lock-fontify-buffer)
@@ -395,11 +429,7 @@ for which the first args match."
     (while (search-forward "module procedure" nil t)
       (let ((names (buffer-substring-no-properties
                     (point)
-                    (save-excursion
-                      (when (re-search-forward "!" (line-end-position) t)
-                        (delete-region (match-beginning 0)
-                                       (line-end-position)))
-                      (line-end-position)))))
+                    (line-end-position))))
         (setf (f90-interface-specialisers interface)
               (make-hash-table :test 'equal))
         (mapc (lambda (x)
@@ -421,6 +451,10 @@ for which the first args match."
 
 (defun f90-arg-types (names)
   (loop for arg in names
+        for subspec = nil then nil
+        if (string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" arg)
+        do (setq subspec (match-string 2 arg)
+                 arg (match-string 1 arg))
         collect (save-excursion
                   (save-restriction
                     (when (re-search-forward
@@ -429,7 +463,26 @@ for which the first args match."
                       (let ((type (match-string 1)))
                         (when (string-match ",[ \t]*intent([^(]+)" type)
                           (setq type (replace-match "" nil t type)))
-                        type))))))
+                        (f90-get-type-subtype type subspec)))))))
+
+(defsubst f90-get-type (type)
+  (gethash type f90-types))
+
+(defsubst f90-get-slot-type (slot type)
+  (let ((fn (intern-soft (format "f90-type.%s-%s" type slot))))
+    (when fn
+      (funcall fn (f90-get-type type)))))
+
+(defun f90-get-type-subtype (type subspec)
+  (cond ((null subspec)
+         (list type))
+        ((string-match "\\`\\([^%]+?\\)[ \t]*%\\(.+\\)\\'" subspec)
+         (f90-get-type-subtype (car
+                                (f90-get-slot-type (match-string 1 subspec)
+                                                  type))
+                               (match-string 2 subspec)))
+        (t
+         (f90-get-slot-type subspec type))))
 
 (defun f90-arglist-types ()
   (save-excursion
@@ -464,7 +517,7 @@ for which the first args match."
 
 (defun f90-approx-arglist-match (arglist specialiser &optional match-sub-list)
   (let* ((n-passed-args (length arglist))
-         (spec-arglist (f90-specialiser-arglist specialiser))
+         (spec-arglist (mapcar 'car (f90-specialiser-arglist specialiser)))
          (n-spec-args (length spec-arglist))
          (n-required-args (f90-count-non-optional-args spec-arglist)))
     (when (or match-sub-list
@@ -477,14 +530,34 @@ for which the first args match."
             when (string-match ",[ \t]*optional" spec-arg)
             do (setq spec-arg (replace-match "" nil t spec-arg))
             ;; as can targets
-            when (string-match ", [ \t]*target" spec-arg)
+            when (string-match ",[ \t]*target" spec-arg)
             do (setq spec-arg (replace-match "" nil t spec-arg))
-            if (or (null arg) (string= arg spec-arg))
+            if (or (null arg) (f90-match-types arg spec-arg))
             do (setq match t)
             else
             do (return nil)
             finally (return match)))))
 
+(defun f90-match-types (parsed-type type)
+  ;; Ignore target in type
+  (when (string-match ",[ \t]*target" (car parsed-type))
+    (setf (car parsed-type) (replace-match "" nil t (car parsed-type))))
+  (if (null (cdr parsed-type))
+      (string= (f90-trim-string (car parsed-type)) type)
+    (and (string-match (format "\\`[ \t]*%s"
+                               (f90-trim-string (car parsed-type))) type)
+         (loop for thing in (cdr parsed-type)
+               if (and (consp thing) (string= (car thing) "dimension"))
+               do (unless (and (string-match "dimension[ \t]*(\\([^)]+\\))"
+                                             type)
+                               (= (cdr thing) (1+ (f90-count-commas
+                                                   (match-string 1 type)))))
+                    (return nil))
+               else
+               do (unless (string-match thing type)
+                    (return nil))
+               finally (return t)))))
+
 (defun f90-end-of-arglist ()
   (save-excursion
     (let ((level 0))
@@ -530,7 +603,7 @@ for which the first args match."
     (goto-char (point-min))
     (set-syntax-table f90-mode-syntax-table)
     (while (not (eobp))
-      (when (nth 4 (parse-partial-sexp (point-min) (point)))
+      (when (nth 4 (parse-partial-sexp (line-beginning-position) (point)))
         (delete-region (max (1- (point)) (line-beginning-position))
                        (line-end-position)))
       (forward-char 1))))
@@ -540,9 +613,9 @@ for which the first args match."
   (let ((names-list (f90-split-arglist names)))
     (loop for name in names-list
           if (string-match "\\`\\([^=]+\\)[ \t]*=.*\\'" name)
-          collect (match-string 1 name)
+          collect (f90-trim-string (match-string 1 name))
           else
-          collect name)))
+          collect (f90-trim-string name))))
 
 (defun f90-parse-single-type-declaration ()
   (when (looking-at "^[ \t]*\\(.*?\\)[ \t]*::[ \t]*\\(.*\\)$")
@@ -586,26 +659,22 @@ for which the first args match."
                   collect `(,(make-symbol name) ',rest
                             :read-only t))))))
 
-(defun f90-parse-type-definition (str)
-  (with-temp-buffer
-    (let (type slots slot)
-      (insert str)
-      (goto-char (point-min))
-      (f90-clean-comments)
-      (f90-clean-continuation-lines)
-      (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+\\)[ \t]*$" nil t)
-        (error "Trying parse a type but no type found"))
-      (setq type (match-string 1))
-      (save-excursion
-        (unless (re-search-forward "^[ \t]*end[ \t]+type" nil t)
-          (error "Unable to find end of type %s" type))
-        (delete-region (line-beginning-position) (line-end-position)))
-      (while (not (eobp))
-        (setq slot (f90-parse-single-type-declaration))
-        (when slot
-          (setf slots (nconc slot slots)))
-        (forward-line 1))
-      (eval (f90-make-type-struct type slots)))))
+(defun f90-parse-type-definition ()
+  (let (type slots slot fn)
+    (goto-char (point-min))
+    (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+?\\)[ \t]*$" nil t)
+      (error "Trying parse a type but no type found"))
+    (setq type (format "type(%s)" (match-string 1)))
+    (while (not (eobp))
+      (setq slot (f90-parse-single-type-declaration))
+      (when slot
+        (setf slots (nconc slot slots)))
+      (forward-line 1))
+    (eval (f90-make-type-struct type slots))
+    (setq fn (intern-soft (format "make-f90-type.%s" type)))
+    (unless fn
+      (error "Something bad went wrong parsing type definition %s" type))
+    (setf (gethash type f90-types) (funcall fn))))
 
 (provide 'f90-interface-browser)
 

commit ffedb5c68cd78a405d72feb25bd31153487023e8
Author: Lawrence Mitchell <address@hidden>
Date:   Sat Jul 9 00:21:51 2011 +0100

    Whitespace fixes

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 4a28ae2..098ed3b 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -174,7 +174,7 @@ If INTERFACES is nil use `f90-all-interfaces' instead."
                (setf (gethash name existing)
                      val)))
            new))
-  
+
 (defun f90-specialisers (name interfaces)
   "Return all specialisers for NAME in INTERFACES."
   (f90-interface-specialisers (f90-get-interface name interfaces)))
@@ -264,7 +264,6 @@ for which the first args match."
         (f90-interface-browser-mode)
         (setq f90-buffer-to-switch-to buf)
         (setq f90-interface-type type)
-        
         (pop-to-buffer (current-buffer))))))
 
 (defun f90-format-specialised-arglist (arglist)
@@ -272,6 +271,7 @@ for which the first args match."
                (or x "UNION-TYPE"))
              arglist
              "; "))
+
 (define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
   "Major mode for browsing f90 interfaces."
   (setq buffer-read-only t)
@@ -355,7 +355,6 @@ for which the first args match."
     (insert (mapconcat (lambda (x)
                          (format "%s :: foo" x))
                        arglist "\n"))
-                       
     (f90-mode)
     (font-lock-fontify-buffer)
     (goto-char (point-min))
@@ -365,7 +364,7 @@ for which the first args match."
                                                (- (line-end-position) 7))
                      do (forward-line 1))
                "; ")))
-      
+
 (defun f90-set-public-attribute (interfaces)
   "Set public/private flag on all INTERFACES."
   (save-excursion
@@ -425,12 +424,12 @@ for which the first args match."
         collect (save-excursion
                   (save-restriction
                     (when (re-search-forward
-                               (format "^[ \t]*\\([^!\n].+?\\)[ 
\t]*::.*\\<%s\\>"
-                                       arg) nil t)
-                          (let ((type (match-string 1)))
-                            (when (string-match ",[ \t]*intent([^(]+)" type)
-                              (setq type (replace-match "" nil t type)))
-                            type))))))
+                           (format "^[ \t]*\\([^!\n].+?\\)[ \t]*::.*\\<%s\\>"
+                                   arg) nil t)
+                      (let ((type (match-string 1)))
+                        (when (string-match ",[ \t]*intent([^(]+)" type)
+                          (setq type (replace-match "" nil t type)))
+                        type))))))
 
 (defun f90-arglist-types ()
   (save-excursion
@@ -486,7 +485,6 @@ for which the first args match."
             do (return nil)
             finally (return match)))))
 
-
 (defun f90-end-of-arglist ()
   (save-excursion
     (let ((level 0))

commit 5ebd16165ac31ffa6d5923f053e483d9380d3441
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 8 23:47:49 2011 +0100

    Add sketch of type definition parsing
    
    We can now parse a derived type definition into its component slots
    and produce a lisp struct mapping on to it. For example with a type
    definition of:
    
     type foo
        integer, dimension(:), pointer :: n=>null()
        real, dimension(:, :), allocatable :: p
        character :: char
        integer :: len
     end type foo
    
    We produce a struct defined by:
    
     (defstruct f90-type.foo
       (n '("integer" ("dimension" . 1) "pointer") :read-only t)
       (p '("real" ("dimension" . 2) "allocatable") :read-only t)
       (char '("character") :read-only t)
       (len '("integer") :read-only t)
    
    The aim of this is to do better argument type derivation.  So that if
    we have:
    
     ...
     type(foo) :: a
     ...
     call add(a%len)
    
    we can figure out that add is being called with an integer argument.

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 404ca7b..4a28ae2 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -47,20 +47,28 @@
 
 ;;; Code:
 
-(require 'cl)
+(eval-when-compile (require 'cl))
 (require 'thingatpt)
+(require 'f90)
 
 (defstruct f90-interface
   (name "" :read-only t)
   (publicp nil)
   specialisers)
 
+
 (defstruct f90-specialiser
   (name "" :read-only t)
   (type "")
   (arglist "")
   (location))
 
+(defvar f90-interface-type nil)
+(make-variable-buffer-local 'f90-interface-type)
+
+(defvar f90-buffer-to-switch-to nil)
+(make-variable-buffer-local 'f90-buffer-to-switch-to)
+
 (defun f90-clean-continuation-lines ()
   "Splat Fortran continuation lines in the current buffer onto one line."
   (save-excursion
@@ -264,11 +272,6 @@ for which the first args match."
                (or x "UNION-TYPE"))
              arglist
              "; "))
-(defvar f90-interface-type nil)
-(make-variable-buffer-local 'f90-interface-type)
-
-(defvar f90-buffer-to-switch-to nil)
-(make-variable-buffer-local 'f90-buffer-to-switch-to)
 (define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
   "Major mode for browsing f90 interfaces."
   (setq buffer-read-only t)
@@ -377,6 +380,7 @@ for which the first args match."
                       (line-end-position))))
           ;; Set default
           (maphash (lambda (k v)
+                     (ignore k)
                      (setf (f90-interface-publicp v) public))
                    interfaces)
           ;; Override for those specified
@@ -449,8 +453,7 @@ for which the first args match."
         (f90-arg-types names)))))
 
 (defun f90-match-arglist-to-specialisers (arglist interface)
-  (let ((specialisers (f90-interface-specialisers interface))
-        (result nil))
+  (let ((specialisers (f90-interface-specialisers interface)))
     (loop for spec being the hash-values of specialisers
           when (f90-approx-arglist-match arglist
                                          (f90-specialiser-arglist spec))
@@ -524,6 +527,88 @@ for which the first args match."
         (forward-char))
       (nreverse ret))))
 
+(defun f90-clean-comments ()
+  (save-excursion
+    (goto-char (point-min))
+    (set-syntax-table f90-mode-syntax-table)
+    (while (not (eobp))
+      (when (nth 4 (parse-partial-sexp (point-min) (point)))
+        (delete-region (max (1- (point)) (line-beginning-position))
+                       (line-end-position)))
+      (forward-char 1))))
+
+(defun f90-parse-names-list (names)
+  "Return a list of names from the RHS of a :: type declaration."
+  (let ((names-list (f90-split-arglist names)))
+    (loop for name in names-list
+          if (string-match "\\`\\([^=]+\\)[ \t]*=.*\\'" name)
+          collect (match-string 1 name)
+          else
+          collect name)))
+
+(defun f90-parse-single-type-declaration ()
+  (when (looking-at "^[ \t]*\\(.*?\\)[ \t]*::[ \t]*\\(.*\\)$")
+    (let ((dec (match-string 1))
+          (names (f90-parse-names-list (match-string 2))))
+      (loop for name in names
+            collect (cons name (f90-split-declaration dec))))))
+
+(defsubst f90-count-commas (str)
+  (loop for c across str
+        when (eq c ?\,)
+        sum 1))
+
+(defun f90-split-declaration (dec)
+  (let ((things (f90-split-arglist dec)))
+    (cons (car things)
+          (loop for thing in (cdr things)
+                if (string-match "dimension(\\([^)]+\\))" thing)
+                collect (cons "dimension"
+                              (1+ (f90-count-commas (match-string 1 thing))))
+                else if (string-match "character([^)]+)" thing)
+                collect (cons "character" "*")
+                else
+                collect thing))))
+
+(defmacro f90-make-type-struct (type slots)
+  (let ((struct-name (make-symbol "struct-name")))
+    `(let ((,struct-name (make-symbol (format "f90-type.%s" ,type))))
+       `(defstruct ,,struct-name
+          ,@(loop for (name . rest) in slots
+                  if (string-match "\\([^(]+\\)(\\([^)]+\\))" name)
+                  do (progn (if (assoc "dimension" (cdr rest))
+                                (setcdr (assoc "dimension" (cdr rest))
+                                        (1+ (f90-count-commas
+                                             (match-string 2 name))))
+                              (push (cons "dimension"
+                                          (1+ (f90-count-commas
+                                               (match-string 2 name))))
+                                    (cdr rest)))
+                            (setq name (match-string 1 name)))
+                  collect `(,(make-symbol name) ',rest
+                            :read-only t))))))
+
+(defun f90-parse-type-definition (str)
+  (with-temp-buffer
+    (let (type slots slot)
+      (insert str)
+      (goto-char (point-min))
+      (f90-clean-comments)
+      (f90-clean-continuation-lines)
+      (unless (re-search-forward "^[ \t]*type[ \t]+\\(.+\\)[ \t]*$" nil t)
+        (error "Trying parse a type but no type found"))
+      (setq type (match-string 1))
+      (save-excursion
+        (unless (re-search-forward "^[ \t]*end[ \t]+type" nil t)
+          (error "Unable to find end of type %s" type))
+        (delete-region (line-beginning-position) (line-end-position)))
+      (while (not (eobp))
+        (setq slot (f90-parse-single-type-declaration))
+        (when slot
+          (setf slots (nconc slot slots)))
+        (forward-line 1))
+      (eval (f90-make-type-struct type slots)))))
+
 (provide 'f90-interface-browser)
 
 ;;; f90-interface-browser.el ends here

commit 70c799c8325115b4df7cd2de23d5ad6ff768f6d5
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 8 14:54:28 2011 +0100

    Require thingatpt (for word-at-point)

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index e1b03e9..404ca7b 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -48,6 +48,7 @@
 ;;; Code:
 
 (require 'cl)
+(require 'thingatpt)
 
 (defstruct f90-interface
   (name "" :read-only t)

commit 16d56833df80ce6656761541e9ca1ad67c5f3375
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 8 14:47:12 2011 +0100

    Fix setting of public/private attribute on interfaces

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index 3059ce0..e1b03e9 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -363,16 +363,27 @@ for which the first args match."
                "; ")))
       
 (defun f90-set-public-attribute (interfaces)
+  "Set public/private flag on all INTERFACES."
   (save-excursion
-    (while (re-search-forward "^[ \t]*public[ \t]+" nil t)
-      (let ((names (buffer-substring-no-properties
-                    (match-end 0)
-                    (line-end-position))))
-        (mapc (lambda (name)
-                (let ((interface (f90-get-interface name interfaces)))
-                  (when interface
-                    (setf (f90-interface-publicp interface) t))))
-              (split-string names "[, \t]" t))))))
+    ;; Default public unless private is specified.
+    (let ((public (not (save-excursion
+                         (re-search-forward "^[ \t]*private[ \t]*$" nil t)))))
+      (while (re-search-forward (format "^[ \t]*%s[ \t]+"
+                                        (if public "private" "public"))
+                                nil t)
+        (let ((names (buffer-substring-no-properties
+                      (match-end 0)
+                      (line-end-position))))
+          ;; Set default
+          (maphash (lambda (k v)
+                     (setf (f90-interface-publicp v) public))
+                   interfaces)
+          ;; Override for those specified
+          (mapc (lambda (name)
+                  (let ((interface (f90-get-interface name interfaces)))
+                    (when interface
+                      (setf (f90-interface-publicp interface) (not public)))))
+                (split-string names "[, \t]" t)))))))
 
 (defun f90-populate-specialisers (interface)
   (save-excursion

commit ad584d8383ca2447451c4105b31b96f31ef60b81
Author: Lawrence Mitchell <address@hidden>
Date:   Fri Jul 8 14:34:52 2011 +0100

    Add more function documentation

diff --git a/f90-interface-browser.el b/f90-interface-browser.el
index def9257..3059ce0 100644
--- a/f90-interface-browser.el
+++ b/f90-interface-browser.el
@@ -77,6 +77,9 @@
         do (f90-parse-interfaces file f90-all-interfaces)))
 
 (defun f90-get-interface (name &optional interfaces)
+  "Get the interface with NAME from INTERFACES.
+
+If INTERFACES is nil use `f90-all-interfaces' instead."
   (gethash name (or interfaces f90-all-interfaces)))
 
 (defsetf f90-get-interface (name &optional interfaces) (val)
@@ -164,6 +167,7 @@
            new))
   
 (defun f90-specialisers (name interfaces)
+  "Return all specialisers for NAME in INTERFACES."
   (f90-interface-specialisers (f90-get-interface name interfaces)))
 
 (defun f90-valid-interface-name (name)
@@ -171,6 +175,10 @@
   (gethash name f90-all-interfaces))
 
 (defun f90-find-tag-interface (name)
+  "List all interfaces matching NAME.
+
+Restricts list to those matching the (possibly typed) arglist of the
+word at point."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Interface (default %s): " def)
@@ -182,6 +190,12 @@
 
 (defun f90-browse-interface-specialisers (name &optional arglist-to-match
                                                first-args-to-match)
+  "Browse all interfaces matching NAME.
+
+If ARGLIST-TO-MATCH is non-nil restrict to those interfaces that match
+it.
+If FIRST-ARGS-TO-MATCH is non-nil only restrict to those interfaces
+for which the first args match."
   (interactive (let ((def (word-at-point)))
                  (list (completing-read
                         (format "Interface%s: "
@@ -255,11 +269,20 @@
 (defvar f90-buffer-to-switch-to nil)
 (make-variable-buffer-local 'f90-buffer-to-switch-to)
 (define-derived-mode f90-interface-browser-mode fundamental-mode "IBrowse"
-  ""
+  "Major mode for browsing f90 interfaces."
   (setq buffer-read-only t)
   (set-buffer-modified-p nil))
 
+(let ((map (make-sparse-keymap)))
+  (define-key map (kbd "RET") 'f90-find-definition)
+  (define-key map (kbd "<down>") 'f90-next-definition)
+  (define-key map (kbd "<up>") 'f90-previous-definition)
+  (define-key map (kbd "q") 'f90-quit-browser)
+  (define-key map (kbd "<mouse-1>") 'f90-mouse-find-definition)
+  (setq f90-interface-browser-mode-map map))
+
 (defun f90-next-definition (&optional arg)
+  "Go to the next ARG'th specialiser definition."
   (interactive "p")
   (unless arg
     (setq arg 1))
@@ -271,6 +294,7 @@
     (decf arg)))
 
 (defun f90-previous-definition (&optional arg)
+  "Go to the previous ARG'th specialiser definition."
   (interactive "p")
   (unless arg
     (setq arg 1))
@@ -282,16 +306,9 @@
                          nil (point-min))))
     (f90-next-definition 1)
     (decf arg)))
-                                                
-(let ((map (make-sparse-keymap)))
-  (define-key map (kbd "RET") 'f90-find-definition)
-  (define-key map (kbd "<down>") 'f90-next-definition)
-  (define-key map (kbd "<up>") 'f90-previous-definition)
-  (define-key map (kbd "q") 'f90-quit-browser)
-  (define-key map (kbd "<mouse-1>") 'f90-mouse-find-definition)
-  (setq f90-interface-browser-mode-map map))
 
 (defun f90-mouse-find-definition (e)
+  "Visit the definition at the position of the event E."
   (interactive "e")
   (let ((win (posn-window (event-end e)))
         (point (posn-point (event-end e))))
@@ -302,12 +319,14 @@
       (f90-find-definition))))
 
 (defun f90-quit-browser ()
+  "Quit the interface browser."
   (interactive)
   (let ((buf f90-buffer-to-switch-to))
     (kill-buffer (current-buffer))
     (pop-to-buffer buf)))
 
 (defun f90-find-definition ()
+  "Visit the definition at `point'."
   (interactive)
   (let ((location (get-text-property (point) 'f90-specialiser-location))
         (name (get-text-property (point) 'f90-specialiser-name))
@@ -327,6 +346,7 @@
       (error "No definition at point"))))
 
 (defun f90-fontify-arglist (arglist)
+  "Fontify ARGLIST using `f90-mode'."
   (with-temp-buffer
     (insert (mapconcat (lambda (x)
                          (format "%s :: foo" x))

commit bfbd616a226412c43c5a5d82a4f418157c16b560
Merge: 2c3d17b 62c84fb
Author: Chris Wanstrath <address@hidden>
Date:   Thu Jul 7 11:45:42 2011 -0700

    Merge pull request #33 from knu/pr-coffee-compiled-file-name
    
    Add a function coffee-compiled-file-name for ease of scripting.


commit 62c84fb393697087cd59d064b4db114c4553b390
Author: Akinori MUSHA <address@hidden>
Date:   Wed Jul 6 19:01:45 2011 +0900

    Add a function coffee-compiled-file-name for ease of scripting.

diff --git a/README.md b/README.md
index 28da042..c2ff614 100644
--- a/README.md
+++ b/README.md
@@ -190,6 +190,13 @@ compile-on-save minor mode in `coffee-mode`.  To enable it 
by default:
 
     (add-hook 'coffee-mode-hook '(lambda () (coffee-cos-mode t)))
 
+To enable it only if it looks like you may want to:
+
+    (add-hook 'coffee-mode-hook '(lambda ()
+                                   (and (file-exists-p (buffer-file-name))
+                                        (file-exists-p 
(coffee-compiled-file-name))
+                                        (coffee-cos-mode t))))
+
 ### coffee-repl
 
 Starts a repl in a new buffer using `coffee-command`.
@@ -222,12 +229,11 @@ Naturally. Example:
       (setq coffee-command "~/dev/coffee"))
 
       ;; Compile '.coffee' files on every save
-      (add-hook 'after-save-hook
-          '(lambda ()
-             (when (string-match "\.coffee$" (buffer-name))
-              (coffee-compile-file))))
+      (and (file-exists-p (buffer-file-name))
+           (file-exists-p (coffee-compiled-file-name))
+           (coffee-cos-mode t))))
 
-    (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))
+    (add-hook 'coffee-mode-hook 'coffee-custom))
 
 ## Configuration
 
diff --git a/coffee-mode.el b/coffee-mode.el
index 9b8abce..f889f5d 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -156,12 +156,17 @@ path."
 
   (pop-to-buffer "*CoffeeREPL*"))
 
+(defun coffee-compiled-file-name (&optional filename)
+  "Returns the name of the JavaScript file compiled from a CoffeeScript file.
+If FILENAME is omitted, the current buffer's file name is used."
+  (concat (file-name-sans-extension (or filename (buffer-file-name))) ".js"))
+
 (defun coffee-compile-file ()
   "Compiles and saves the current file to disk. Doesn't open in a buffer.."
   (interactive)
   (let ((compiler-output (shell-command-to-string (coffee-command-compile 
(buffer-file-name)))))
     (if (string= compiler-output "")
-        (message "Compiled and saved %s" (concat (substring (buffer-file-name) 
0 -6) "js"))
+        (message "Compiled and saved %s" (coffee-compiled-file-name))
       (message (car (split-string compiler-output "[\n\r]+"))))))
 
 (defun coffee-compile-buffer ()

commit 2c3d17bf271873d91047d858eca5d321fa3cbd84
Merge: 74a9135 5ecae75
Author: Chris Wanstrath <address@hidden>
Date:   Fri Jul 1 14:19:33 2011 -0700

    Merge pull request #25 from knu/master
    
    Add a minor mode coffee-cos-mode


commit 5ecae750b48d7ee7ad2207bd503e43b8b8160aee
Author: Akinori MUSHA <address@hidden>
Date:   Fri Jul 1 14:20:03 2011 +0900

    Mention the compile-on-save minor mode.

diff --git a/README.md b/README.md
index d0a4d77..28da042 100644
--- a/README.md
+++ b/README.md
@@ -183,6 +183,13 @@ Bind it:
 
     (define-key coffee-mode-map [(meta R)] 'coffee-compile-region)
 
+### Compile-on-save
+
+Hitting the key sequence `C-c C-o C-s` turns on (toggles) the
+compile-on-save minor mode in `coffee-mode`.  To enable it by default:
+
+    (add-hook 'coffee-mode-hook '(lambda () (coffee-cos-mode t)))
+
 ### coffee-repl
 
 Starts a repl in a new buffer using `coffee-command`.

commit 393dbd781b3f0dcb4ac90cfde1ba8e3d734d8d41
Merge: 6eb6d99 74a9135
Author: Akinori MUSHA <address@hidden>
Date:   Thu Jun 23 17:53:02 2011 +0900

    Merge remote-tracking branch 'defunkt/master'


commit 444c1b0ed0731910c08fd3708415a5300b38e39b
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jun 23 08:18:20 2011 +0200

    (ioccur): Disable pop-up-frames.

diff --git a/ioccur.el b/ioccur.el
index f2ff024..efa2443 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -928,80 +928,81 @@ Special NOTE for terms:
 When you quit incremental search with RET, see `ioccur-mode'
 for commands provided in the `ioccur-buffer'."
   (interactive "P")
-  (setq ioccur-exit-and-quit-p nil)
-  (setq ioccur-success nil)
-  (setq ioccur-current-buffer (buffer-name (current-buffer)))
-  (when ioccur-fontify-buffer-p
-    (message "Fontifying buffer...Please wait it could be long.")
-    (jit-lock-fontify-now) (message nil))
-  (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
-  (setq ioccur-last-window-configuration (current-window-configuration))
-  (if (and (not initial-input)
-           (get-buffer ioccur-buffer)
-           (not (get-buffer-window ioccur-buffer)))
-      ;; An hidden `ioccur-buffer' exists jump to it and reuse it.
-      (switch-to-buffer-other-window ioccur-buffer t)
-      ;; `ioccur-buffer' doesn't exists or is visible, start searching
-      ;; Creating a new `ioccur-buffer' or reusing the visible one after
-      ;; erasing it.
-      (let* ((init-str (if initial-input
-                           (if (stringp initial-input)
-                               initial-input (thing-at-point 'symbol))
-                           ""))
-             (len      (length init-str))
-             (curpos   (point))
-             (inhibit-read-only t)
-             (cur-mode (with-current-buffer ioccur-current-buffer
-                         (prog1
-                             major-mode
-                           ;; If current `major-mode' is wdired
-                           ;; Turn it off.
-                           (when (eq major-mode 'wdired-mode)
-                             (wdired-change-to-dired-mode)))))
-             str-no-prop)
-        (set-text-properties 0 len nil init-str)
-        (setq str-no-prop init-str)
-        ;(switch-to-buffer-other-window (get-buffer-create ioccur-buffer) t)
-        (pop-to-buffer (get-buffer-create ioccur-buffer))
-        (ioccur-mode)
-        (unwind-protect
-             ;; Start incremental search.
-             (progn
-               (ioccur-start-timer)
-               (ioccur-read-search-input str-no-prop curpos))
-          ;; At this point incremental search loop is exited.
-          (progn
-            (ioccur-cancel-search)
-            (kill-local-variable 'mode-line-format)
-            (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
-              (setq ioccur-quit-flag t))
-            (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
-                   (kill-buffer ioccur-buffer)
-                   (pop-to-buffer ioccur-current-buffer)
-                   (when ioccur-match-overlay
-                     (delete-overlay ioccur-match-overlay))
-                   (set-window-configuration ioccur-last-window-configuration)
-                   (goto-char curpos)
-                   (ioccur-send-message)
-                   ;; If `ioccur-message' is non--nil, thats mean we exit
-                   ;; with a specific action other than `C-g',
-                   ;; e.g kill-as-sexp, so we save history.
-                   (when ioccur-message (ioccur-save-history)))
-                  (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
-                   (ioccur-jump-and-quit)
-                   (kill-buffer ioccur-buffer)
-                   (ioccur-send-message) (ioccur-save-history))
-                  (t                   ; Jump keeping `ioccur-buffer'.
-                   (ioccur-jump)
-                   (pop-to-buffer ioccur-buffer)
-                   (setq buffer-read-only t)
-                   (ioccur-save-history)))
-            ;; Maybe reenable `wdired-mode'.
-            (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
-            (setq ioccur-count-occurences 0)
-            (setq ioccur-quit-flag nil)
-            (setq ioccur-message nil)
-            (setq ioccur-search-function ioccur-default-search-function))))))
+  (let (pop-up-frames)
+    (setq ioccur-exit-and-quit-p nil)
+    (setq ioccur-success nil)
+    (setq ioccur-current-buffer (buffer-name (current-buffer)))
+    (when ioccur-fontify-buffer-p
+      (message "Fontifying buffer...Please wait it could be long.")
+      (jit-lock-fontify-now) (message nil))
+    (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
+    (setq ioccur-last-window-configuration (current-window-configuration))
+    (if (and (not initial-input)
+             (get-buffer ioccur-buffer)
+             (not (get-buffer-window ioccur-buffer)))
+        ;; An hidden `ioccur-buffer' exists jump to it and reuse it.
+        (switch-to-buffer-other-window ioccur-buffer t)
+        ;; `ioccur-buffer' doesn't exists or is visible, start searching
+        ;; Creating a new `ioccur-buffer' or reusing the visible one after
+        ;; erasing it.
+        (let* ((init-str (if initial-input
+                             (if (stringp initial-input)
+                                 initial-input (thing-at-point 'symbol))
+                             ""))
+               (len      (length init-str))
+               (curpos   (point))
+               (inhibit-read-only t)
+               (cur-mode (with-current-buffer ioccur-current-buffer
+                           (prog1
+                               major-mode
+                             ;; If current `major-mode' is wdired
+                             ;; Turn it off.
+                             (when (eq major-mode 'wdired-mode)
+                               (wdired-change-to-dired-mode)))))
+               str-no-prop)
+          (set-text-properties 0 len nil init-str)
+          (setq str-no-prop init-str)
+                                        ;(switch-to-buffer-other-window 
(get-buffer-create ioccur-buffer) t)
+          (pop-to-buffer (get-buffer-create ioccur-buffer))
+          (ioccur-mode)
+          (unwind-protect
+               ;; Start incremental search.
+               (progn
+                 (ioccur-start-timer)
+                 (ioccur-read-search-input str-no-prop curpos))
+            ;; At this point incremental search loop is exited.
+            (progn
+              (ioccur-cancel-search)
+              (kill-local-variable 'mode-line-format)
+              (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
+                (setq ioccur-quit-flag t))
+              (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
+                     (kill-buffer ioccur-buffer)
+                     (pop-to-buffer ioccur-current-buffer)
+                     (when ioccur-match-overlay
+                       (delete-overlay ioccur-match-overlay))
+                     (set-window-configuration 
ioccur-last-window-configuration)
+                     (goto-char curpos)
+                     (ioccur-send-message)
+                     ;; If `ioccur-message' is non--nil, thats mean we exit
+                     ;; with a specific action other than `C-g',
+                     ;; e.g kill-as-sexp, so we save history.
+                     (when ioccur-message (ioccur-save-history)))
+                    (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
+                     (ioccur-jump-and-quit)
+                     (kill-buffer ioccur-buffer)
+                     (ioccur-send-message) (ioccur-save-history))
+                    (t                 ; Jump keeping `ioccur-buffer'.
+                     (ioccur-jump)
+                     (pop-to-buffer ioccur-buffer)
+                     (setq buffer-read-only t)
+                     (ioccur-save-history)))
+              ;; Maybe reenable `wdired-mode'.
+              (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
+              (setq ioccur-count-occurences 0)
+              (setq ioccur-quit-flag nil)
+              (setq ioccur-message nil)
+              (setq ioccur-search-function 
ioccur-default-search-function)))))))
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."

commit a8ce5598c5067f19f2cba9cac77d5d6390c7f1fe
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jun 18 15:15:57 2011 +0200

    Removed superfluous quotes.

diff --git a/company-abbrev.el b/company-abbrev.el
index 16cdeed..57939e8 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -30,14 +30,14 @@
   "A `company-mode' completion back-end for abbrev."
   (interactive (list 'interactive))
   (case command
-        ('interactive (company-begin-backend 'company-abbrev
-                                             'company-abbrev-insert))
-        ('prefix (company-grab-symbol))
-        ('candidates (nconc
-                      (delete "" (all-completions arg global-abbrev-table))
-                      (delete "" (all-completions arg local-abbrev-table))))
-        ('meta (abbrev-expansion arg))
-        ('require-match t)))
+    (interactive (company-begin-backend 'company-abbrev
+                                        'company-abbrev-insert))
+    (prefix (company-grab-symbol))
+    (candidates (nconc
+                 (delete "" (all-completions arg global-abbrev-table))
+                 (delete "" (all-completions arg local-abbrev-table))))
+    (meta (abbrev-expansion arg))
+    (require-match t)))
 
 (provide 'company-abbrev)
 ;;; company-abbrev.el ends here
diff --git a/company-clang.el b/company-clang.el
index f4725c7..5bd5535 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -204,21 +204,21 @@ Completions only work correctly when the buffer has been 
saved.
 `company-clang-auto-save' determines whether to do this automatically."
   (interactive (list 'interactive))
   (case command
-        ('interactive (company-begin-backend 'company-clang))
-        ('init (unless company-clang-executable
-                 (error "Company found no clang executable"))
-               (when (version< (company-clang-version)
-                               company-clang-required-version)
-                 (error "Company requires clang version 1.1")))
-        ('prefix (and (memq major-mode company-clang-modes)
-                      buffer-file-name
-                      company-clang-executable
-                      (not (company-in-string-or-comment))
-                      (or (company-grab-symbol) 'stop)))
-        ('candidates (company-clang--candidates arg))
-        ('post-completion (and (derived-mode-p 'objc-mode)
-                               (string-match ":" arg)
-                               (company-clang-objc-templatify arg)))))
+    (interactive (company-begin-backend 'company-clang))
+    (init (unless company-clang-executable
+            (error "Company found no clang executable"))
+          (when (version< (company-clang-version)
+                          company-clang-required-version)
+            (error "Company requires clang version 1.1")))
+    (prefix (and (memq major-mode company-clang-modes)
+                 buffer-file-name
+                 company-clang-executable
+                 (not (company-in-string-or-comment))
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (company-clang--candidates arg))
+    (post-completion (and (derived-mode-p 'objc-mode)
+                          (string-match ":" arg)
+                          (company-clang-objc-templatify arg)))))
 
 (provide 'company-clang)
 ;;; company-clang.el ends here
diff --git a/company-css.el b/company-css.el
index cb80ce0..6c8f4c0 100644
--- a/company-css.el
+++ b/company-css.el
@@ -275,13 +275,13 @@ Returns \"\" if no property found, but feasible at this 
position."
   "A `company-mode' completion back-end for `css-mode'."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-css))
-    ('prefix (and (derived-mode-p 'css-mode)
-                  (or (company-grab company-css-tag-regexp 1)
-                      (company-grab company-css-pseudo-regexp 1)
-                      (company-grab company-css-property-value-regexp 2)
-                      (company-css-grab-property))))
-    ('candidates
+    (interactive (company-begin-backend 'company-css))
+    (prefix (and (derived-mode-p 'css-mode)
+                 (or (company-grab company-css-tag-regexp 1)
+                     (company-grab company-css-pseudo-regexp 1)
+                     (company-grab company-css-property-value-regexp 2)
+                     (company-css-grab-property))))
+    (candidates
      (cond
       ((company-grab company-css-tag-regexp 1)
        (all-completions arg company-css-html-tags))
@@ -293,7 +293,7 @@ Returns \"\" if no property found, but feasible at this 
position."
                          (company-grab company-css-property-value-regexp 1))))
       ((company-css-grab-property)
        (all-completions arg company-css-property-alist))))
-    ('sorted t)))
+    (sorted t)))
 
 (provide 'company-css)
 ;;; company-css.el ends here
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 93f62c9..5d962e2 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -65,17 +65,17 @@ The back-end looks for all symbols in the current buffer 
that aren't in
 comments or strings."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-dabbrev-code))
-    ('prefix (and (or (eq t company-dabbrev-code-modes)
-                      (apply 'derived-mode-p company-dabbrev-code-modes))
-                  (not (company-in-string-or-comment))
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((completion-ignore-case nil))
-                   (company-dabbrev--search
-                    (company-dabbrev-code--make-regexp arg)
-                    company-dabbrev-code-time-limit
-                    company-dabbrev-code-other-buffers t)))
-    ('duplicates t)))
+    (interactive (company-begin-backend 'company-dabbrev-code))
+    (prefix (and (or (eq t company-dabbrev-code-modes)
+                     (apply 'derived-mode-p company-dabbrev-code-modes))
+                 (not (company-in-string-or-comment))
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (let ((completion-ignore-case nil))
+                  (company-dabbrev--search
+                   (company-dabbrev-code--make-regexp arg)
+                   company-dabbrev-code-time-limit
+                   company-dabbrev-code-other-buffers t)))
+    (duplicates t)))
 
 (provide 'company-dabbrev-code)
 ;;; company-dabbrev-code.el ends here
diff --git a/company-dabbrev.el b/company-dabbrev.el
index c5a6081..f4453e9 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -104,15 +104,15 @@ See also `company-dabbrev-time-limit'."
   "A dabbrev-like `company-mode' completion back-end."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-dabbrev))
-    ('prefix (company-grab-word))
-    ('candidates
+    (interactive (company-begin-backend 'company-dabbrev))
+    (prefix (company-grab-word))
+    (candidates
      (mapcar 'downcase
              (company-dabbrev--search (company-dabbrev--make-regexp arg)
                                       company-dabbrev-time-limit
                                       company-dabbrev-other-buffers)))
-    ('ignore-case t)
-    ('duplicates t)))
+    (ignore-case t)
+    (duplicates t)))
 
 (provide 'company-dabbrev)
 ;;; company-dabbrev.el ends here
diff --git a/company-eclim.el b/company-eclim.el
index 8ff0141..f28bdb0 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -123,17 +123,17 @@ Completions only work correctly when the buffer has been 
saved.
 `company-eclim-auto-save' determines whether to do this automatically."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-eclim))
-    ('prefix (and (derived-mode-p 'java-mode 'jde-mode)
-                  buffer-file-name
-                  company-eclim-executable
-                  (company-eclim--project-name)
-                  (not (company-in-string-or-comment))
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates (company-eclim--candidates arg))
-    ('meta (cadr (assoc arg company-eclim--doc)))
+    (interactive (company-begin-backend 'company-eclim))
+    (prefix (and (derived-mode-p 'java-mode 'jde-mode)
+                 buffer-file-name
+                 company-eclim-executable
+                 (company-eclim--project-name)
+                 (not (company-in-string-or-comment))
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (company-eclim--candidates arg))
+    (meta (cadr (assoc arg company-eclim--doc)))
     ;; because "" doesn't return everything
-    ('no-cache (equal arg ""))))
+    (no-cache (equal arg ""))))
 
 (provide 'company-eclim)
 ;;; company-eclim.el ends here
diff --git a/company-elisp.el b/company-elisp.el
index a10fe46..1e2b171 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -109,20 +109,20 @@ Functions are offered for completion only after ' and \(."
   "A `company-mode' completion back-end for `emacs-lisp-mode'."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-elisp))
-    ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
-                  (company-grab-lisp-symbol)))
-    ('candidates (company-elisp-candidates arg))
-    ('meta (company-elisp-doc arg))
-    ('doc-buffer (let ((symbol (intern arg)))
-                   (save-window-excursion
-                     (when (or (ignore-errors (describe-function symbol))
-                               (ignore-errors (describe-variable symbol)))
-                       (help-buffer)))))
-    ('location (let ((sym (intern arg)))
-                 (or (ignore-errors (find-definition-noselect sym nil))
-                     (ignore-errors (find-definition-noselect sym 'defvar))
-                     (ignore-errors (find-definition-noselect sym t)))))))
+    (interactive (company-begin-backend 'company-elisp))
+    (prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
+                 (company-grab-lisp-symbol)))
+    (candidates (company-elisp-candidates arg))
+    (meta (company-elisp-doc arg))
+    (doc-buffer (let ((symbol (intern arg)))
+                  (save-window-excursion
+                    (when (or (ignore-errors (describe-function symbol))
+                              (ignore-errors (describe-variable symbol)))
+                      (help-buffer)))))
+    (location (let ((sym (intern arg)))
+                (or (ignore-errors (find-definition-noselect sym nil))
+                    (ignore-errors (find-definition-noselect sym 'defvar))
+                    (ignore-errors (find-definition-noselect sym t)))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company-etags.el b/company-etags.el
index 55842d2..a4c2f1d 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -61,18 +61,18 @@ buffer automatically."
   "A `company-mode' completion back-end for etags."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-etags))
-    ('prefix (and (memq major-mode company-etags-modes)
-                  (not (company-in-string-or-comment))
-                  (company-etags-buffer-table)
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates (company-etags--candidates arg))
-    ('location (let ((tags-table-list (company-etags-buffer-table)))
-                 (when (fboundp 'find-tag-noselect)
-                   (save-excursion
-                     (let ((buffer (find-tag-noselect arg)))
-                       (cons buffer (with-current-buffer buffer (point))))))))
-    ('sorted t)))
+    (interactive (company-begin-backend 'company-etags))
+    (prefix (and (memq major-mode company-etags-modes)
+                 (not (company-in-string-or-comment))
+                 (company-etags-buffer-table)
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (company-etags--candidates arg))
+    (location (let ((tags-table-list (company-etags-buffer-table)))
+                (when (fboundp 'find-tag-noselect)
+                  (save-excursion
+                    (let ((buffer (find-tag-noselect arg)))
+                      (cons buffer (with-current-buffer buffer (point))))))))
+    (sorted t)))
 
 (provide 'company-etags)
 ;;; company-etags.el ends here
diff --git a/company-files.el b/company-files.el
index 6c0775c..bc76469 100644
--- a/company-files.el
+++ b/company-files.el
@@ -68,13 +68,13 @@
   "a `company-mode' completion back-end existing file names."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-files))
-    ('prefix (company-files-grab-existing-name))
-    ('candidates (company-files-complete arg))
-    ('location (cons (dired-noselect
-                      (file-name-directory (directory-file-name arg))) 1))
-    ('sorted t)
-    ('no-cache t)))
+    (interactive (company-begin-backend 'company-files))
+    (prefix (company-files-grab-existing-name))
+    (candidates (company-files-complete arg))
+    (location (cons (dired-noselect
+                     (file-name-directory (directory-file-name arg))) 1))
+    (sorted t)
+    (no-cache t)))
 
 (provide 'company-files)
 ;;; company-files.el ends here
diff --git a/company-gtags.el b/company-gtags.el
index ed591a0..2630f73 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -65,15 +65,15 @@
   "A `company-mode' completion back-end for GNU Global."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-gtags))
-    ('prefix (and company-gtags-executable
-                  (memq major-mode company-gtags-modes)
-                  (not (company-in-string-or-comment))
-                  (company-gtags--tags-available-p)
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates (company-gtags-fetch-tags arg))
-    ('sorted t)
-    ('location (company-gtags-location arg))))
+    (interactive (company-begin-backend 'company-gtags))
+    (prefix (and company-gtags-executable
+                 (memq major-mode company-gtags-modes)
+                 (not (company-in-string-or-comment))
+                 (company-gtags--tags-available-p)
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (company-gtags-fetch-tags arg))
+    (sorted t)
+    (location (company-gtags-location arg))))
 
 (provide 'company-gtags)
 ;;; company-gtags.el ends here
diff --git a/company-ispell.el b/company-ispell.el
index 236c519..c4acebc 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -46,13 +46,13 @@ If nil, use `ispell-complete-word-dict'."
   "A `company-mode' completion back-end using ispell."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-ispell))
-    ('prefix (when (company-ispell-available)
-               (company-grab-word)))
-    ('candidates (lookup-words arg (or company-ispell-dictionary
-                                       ispell-complete-word-dict)))
-    ('sorted t)
-    ('ignore-case t)))
+    (interactive (company-begin-backend 'company-ispell))
+    (prefix (when (company-ispell-available)
+              (company-grab-word)))
+    (candidates (lookup-words arg (or company-ispell-dictionary
+                                      ispell-complete-word-dict)))
+    (sorted t)
+    (ignore-case t)))
 
 (provide 'company-ispell)
 ;;; company-ispell.el ends here
diff --git a/company-keywords.el b/company-keywords.el
index 1e86705..3efda9e 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -211,17 +211,17 @@
   "A `company-mode' back-end for programming language keywords."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-))
-    ('prefix (and (assq major-mode company-keywords-alist)
-                  (not (company-in-string-or-comment))
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates
+    (interactive (company-begin-backend 'company-))
+    (prefix (and (assq major-mode company-keywords-alist)
+                 (not (company-in-string-or-comment))
+                 (or (company-grab-symbol) 'stop)))
+    (candidates
      (let ((completion-ignore-case nil)
            (symbols (cdr (assq major-mode company-keywords-alist))))
        (all-completions arg (if (consp symbols)
                                 symbols
                               (cdr (assq symbols company-keywords-alist))))))
-    ('sorted t)))
+    (sorted t)))
 
 (provide 'company-keywords)
 ;;; company-keywords.el ends here
diff --git a/company-nxml.el b/company-nxml.el
index bacc1dc..5d05bc6 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -60,66 +60,66 @@
 
 (defun company-nxml-tag (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (derived-mode-p 'nxml-mode)
-                  rng-validate-mode
-                  (company-grab company-nxml-in-tag-name-regexp 1)))
-    ('candidates (company-nxml-prepared
-                   (company-nxml-all-completions arg
-                    (rng-match-possible-start-tag-names))))
-    ('sorted t)))
+    (prefix (and (derived-mode-p 'nxml-mode)
+                 rng-validate-mode
+                 (company-grab company-nxml-in-tag-name-regexp 1)))
+    (candidates (company-nxml-prepared
+                 (company-nxml-all-completions
+                  arg (rng-match-possible-start-tag-names))))
+    (sorted t)))
 
 (defun company-nxml-attribute (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (derived-mode-p 'nxml-mode)
-                  rng-validate-mode
-                  (memq (char-after) '(?\  ?\t ?\n)) ;; outside word
-                  (company-grab rng-in-attribute-regex 1)))
-    ('candidates (company-nxml-prepared
-                   (and (rng-adjust-state-for-attribute
-                         lt-pos (- (point) (length arg)))
-                        (company-nxml-all-completions arg
-                         (rng-match-possible-attribute-names)))))
-    ('sorted t)))
+    (prefix (and (derived-mode-p 'nxml-mode)
+                 rng-validate-mode
+                 (memq (char-after) '(?\  ?\t ?\n)) ;; outside word
+                 (company-grab rng-in-attribute-regex 1)))
+    (candidates (company-nxml-prepared
+                 (and (rng-adjust-state-for-attribute
+                       lt-pos (- (point) (length arg)))
+                      (company-nxml-all-completions
+                       arg (rng-match-possible-attribute-names)))))
+    (sorted t)))
 
 (defun company-nxml-attribute-value (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (derived-mode-p 'nxml-mode)
-                  rng-validate-mode
-                  (and (memq (char-after) '(?' ?\" ?\  ?\t ?\n)) ;; outside 
word
-                       (looking-back company-nxml-in-attribute-value-regexp)
-                       (or (match-string-no-properties 4)
-                           (match-string-no-properties 5)
-                           ""))))
-    ('candidates (company-nxml-prepared
-                   (let (attr-start attr-end colon)
-                     (and (looking-back rng-in-attribute-value-regex lt-pos)
-                          (setq colon (match-beginning 2)
-                                attr-start (match-beginning 1)
-                                attr-end (match-end 1))
-                          (rng-adjust-state-for-attribute lt-pos attr-start)
-                          (rng-adjust-state-for-attribute-value
-                           attr-start colon attr-end)
-                          (all-completions arg
-                           (rng-match-possible-value-strings))))))))
+    (prefix (and (derived-mode-p 'nxml-mode)
+                 rng-validate-mode
+                 (and (memq (char-after) '(?' ?\" ?\  ?\t ?\n)) ;; outside word
+                      (looking-back company-nxml-in-attribute-value-regexp)
+                      (or (match-string-no-properties 4)
+                          (match-string-no-properties 5)
+                          ""))))
+    (candidates (company-nxml-prepared
+                 (let (attr-start attr-end colon)
+                   (and (looking-back rng-in-attribute-value-regex lt-pos)
+                        (setq colon (match-beginning 2)
+                              attr-start (match-beginning 1)
+                              attr-end (match-end 1))
+                        (rng-adjust-state-for-attribute lt-pos attr-start)
+                        (rng-adjust-state-for-attribute-value
+                         attr-start colon attr-end)
+                        (all-completions
+                         arg (rng-match-possible-value-strings))))))))
 
 ;;;###autoload
 (defun company-nxml (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `nxml-mode'."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-nxml))
-    ('prefix (or (company-nxml-tag 'prefix)
-                 (company-nxml-attribute 'prefix)
-                 (company-nxml-attribute-value 'prefix)))
-    ('candidates (cond
-                  ((company-nxml-tag 'prefix)
-                   (company-nxml-tag 'candidates arg))
-                  ((company-nxml-attribute 'prefix)
-                   (company-nxml-attribute 'candidates arg))
-                  ((company-nxml-attribute-value 'prefix)
-                   (sort (company-nxml-attribute-value 'candidates arg)
-                         'string<))))
-    ('sorted t)))
+    (interactive (company-begin-backend 'company-nxml))
+    (prefix (or (company-nxml-tag 'prefix)
+                (company-nxml-attribute 'prefix)
+                (company-nxml-attribute-value 'prefix)))
+    (candidates (cond
+                 ((company-nxml-tag 'prefix)
+                  (company-nxml-tag 'candidates arg))
+                 ((company-nxml-attribute 'prefix)
+                  (company-nxml-attribute 'candidates arg))
+                 ((company-nxml-attribute-value 'prefix)
+                  (sort (company-nxml-attribute-value 'candidates arg)
+                        'string<))))
+    (sorted t)))
 
 (provide 'company-nxml)
 ;;; company-nxml.el ends here
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 67b9a80..344a8be 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -27,23 +27,23 @@
 
 (defun company-oddmuse-get-page-table ()
   (case major-mode
-    ('yaoddmuse-mode (with-no-warnings
-                       (yaoddmuse-get-pagename-table yaoddmuse-wikiname)))
-    ('oddmuse-mode (with-no-warnings
-                     (oddmuse-make-completion-table oddmuse-wiki)))))
+    (yaoddmuse-mode (with-no-warnings
+                      (yaoddmuse-get-pagename-table yaoddmuse-wikiname)))
+    (oddmuse-mode (with-no-warnings
+                    (oddmuse-make-completion-table oddmuse-wiki)))))
 
 ;;;###autoload
 (defun company-oddmuse (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `oddmuse-mode'."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-oddmuse))
-    ('prefix (let ((case-fold-search nil))
-               (and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
-                    (looking-back company-oddmuse-link-regexp (point-at-bol))
-                    (or (match-string 1)
-                        (match-string 2)))))
-    ('candidates (all-completions arg (company-oddmuse-get-page-table)))))
+    (interactive (company-begin-backend 'company-oddmuse))
+    (prefix (let ((case-fold-search nil))
+              (and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
+                   (looking-back company-oddmuse-link-regexp (point-at-bol))
+                   (or (match-string 1)
+                       (match-string 2)))))
+    (candidates (all-completions arg (company-oddmuse-get-page-table)))))
 
 (provide 'company-oddmuse)
 ;;; company-oddmuse.el ends here
diff --git a/company-pysmell.el b/company-pysmell.el
index 4c98f07..83dfebb 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -47,13 +47,13 @@
 This requires pysmell.el and pymacs.el."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-pysmell))
-    ('prefix (and (derived-mode-p 'python-mode)
-                  buffer-file-name
-                  (not (company-in-string-or-comment))
-                  (company-pysmell--available-p)
-                  (company-pysmell--grab-symbol)))
-    ('candidates (delete "" (pysmell-get-all-completions)))))
+    (interactive (company-begin-backend 'company-pysmell))
+    (prefix (and (derived-mode-p 'python-mode)
+                 buffer-file-name
+                 (not (company-in-string-or-comment))
+                 (company-pysmell--available-p)
+                 (company-pysmell--grab-symbol)))
+    (candidates (delete "" (pysmell-get-all-completions)))))
 
 (provide 'company-pysmell)
 ;;; company-pysmell.el ends here
diff --git a/company-ropemacs.el b/company-ropemacs.el
index 92de7d0..e63a8df 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -57,14 +57,14 @@
   "A `company-mode' completion back-end for ropemacs."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-ropemacs))
-    ('prefix (and (derived-mode-p 'python-mode)
-                  (not (company-in-string-or-comment))
-                  (company-ropemacs--grab-symbol)))
-    ('candidates (mapcar (lambda (element) (concat arg element))
-                         (rope-completions)))
-    ('doc-buffer (company-ropemacs-doc-buffer arg))
-    ('location (company-ropemacs-location arg))))
+    (interactive (company-begin-backend 'company-ropemacs))
+    (prefix (and (derived-mode-p 'python-mode)
+                 (not (company-in-string-or-comment))
+                 (company-ropemacs--grab-symbol)))
+    (candidates (mapcar (lambda (element) (concat arg element))
+                        (rope-completions)))
+    (doc-buffer (company-ropemacs-doc-buffer arg))
+    (location (company-ropemacs-location arg))))
 
 (provide 'company-ropemacs)
 ;;; company-ropemacs.el ends here
diff --git a/company-semantic.el b/company-semantic.el
index aec05a9..f22266d 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -97,25 +97,25 @@ Symbols are chained by \".\" or \"->\"."
   "A `company-mode' completion back-end using CEDET Semantic."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-semantic))
-    ('prefix (and (memq major-mode company-semantic-modes)
-                  (semantic-active-p)
-                  (not (company-in-string-or-comment))
-                  (or (company-semantic--grab) 'stop)))
-    ('candidates (if (and (equal arg "")
-                          (not (looking-back "->\\|\\.")))
-                     (company-semantic-completions-raw arg)
-                   (company-semantic-completions arg)))
-    ('meta (funcall company-semantic-metadata-function
-                    (assoc arg company-semantic--current-tags)))
-    ('doc-buffer (company-semantic-doc-buffer
-                  (assoc arg company-semantic--current-tags)))
+    (interactive (company-begin-backend 'company-semantic))
+    (prefix (and (memq major-mode company-semantic-modes)
+                 (semantic-active-p)
+                 (not (company-in-string-or-comment))
+                 (or (company-semantic--grab) 'stop)))
+    (candidates (if (and (equal arg "")
+                         (not (looking-back "->\\|\\.")))
+                    (company-semantic-completions-raw arg)
+                  (company-semantic-completions arg)))
+    (meta (funcall company-semantic-metadata-function
+                   (assoc arg company-semantic--current-tags)))
+    (doc-buffer (company-semantic-doc-buffer
+                 (assoc arg company-semantic--current-tags)))
     ;; because "" is an empty context and doesn't return local variables
-    ('no-cache (equal arg ""))
-    ('location (let ((tag (assoc arg company-semantic--current-tags)))
-                 (when (buffer-live-p (semantic-tag-buffer tag))
-                   (cons (semantic-tag-buffer tag)
-                         (semantic-tag-start tag)))))))
+    (no-cache (equal arg ""))
+    (location (let ((tag (assoc arg company-semantic--current-tags)))
+                (when (buffer-live-p (semantic-tag-buffer tag))
+                  (cons (semantic-tag-buffer tag)
+                        (semantic-tag-start tag)))))))
 
 (provide 'company-semantic)
 ;;; company-semantic.el ends here
diff --git a/company-tempo.el b/company-tempo.el
index b22e72a..efba482 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -43,13 +43,13 @@
   "A `company-mode' completion back-end for tempo."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-tempo
-                                         'company-tempo-insert))
-    ('prefix (or (car (tempo-find-match-string tempo-match-finder)) ""))
-    ('candidates (all-completions arg (tempo-build-collection)))
-    ('meta (company-tempo-meta arg))
-    ('require-match t)
-    ('sorted t)))
+    (interactive (company-begin-backend 'company-tempo
+                                        'company-tempo-insert))
+    (prefix (or (car (tempo-find-match-string tempo-match-finder)) ""))
+    (candidates (all-completions arg (tempo-build-collection)))
+    (meta (company-tempo-meta arg))
+    (require-match t)
+    (sorted t)))
 
 (provide 'company-tempo)
 ;;; company-tempo.el ends here
diff --git a/company-xcode.el b/company-xcode.el
index 396cef8..884a78d 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -100,14 +100,14 @@ valid in most contexts."
   "A `company-mode' completion back-end for Xcode projects."
   (interactive (list 'interactive))
   (case command
-    ('interactive (company-begin-backend 'company-xcode))
-    ('prefix (and company-xcode-xcodeindex-executable
+    (interactive (company-begin-backend 'company-xcode))
+    (prefix (and company-xcode-xcodeindex-executable
+                 (company-xcode-tags)
+                 (not (company-in-string-or-comment))
+                 (or (company-grab-symbol) 'stop)))
+    (candidates (let ((completion-ignore-case nil))
                   (company-xcode-tags)
-                  (not (company-in-string-or-comment))
-                  (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((completion-ignore-case nil))
-                   (company-xcode-tags)
-                   (all-completions arg (company-xcode-tags))))))
+                  (all-completions arg (company-xcode-tags))))))
 
 
 (provide 'company-xcode)
diff --git a/company.el b/company.el
index 4641ab9..d001a9f 100644
--- a/company.el
+++ b/company.el
@@ -48,10 +48,10 @@
 ;;
 ;; (defun company-my-backend (command &optional arg &rest ignored)
 ;;   (case command
-;;     ('prefix (when (looking-back "foo\\>")
-;;                (match-string 0)))
-;;     ('candidates (list "foobar" "foobaz" "foobarbaz"))
-;;     ('meta (format "This value is named %s" arg))))
+;;     (prefix (when (looking-back "foo\\>")
+;;               (match-string 0)))
+;;     (candidates (list "foobar" "foobaz" "foobarbaz"))
+;;     (meta (format "This value is named %s" arg))))
 ;;
 ;; Sometimes it is a good idea to mix two back-ends together, for example to
 ;; enrich gtags with dabbrev-code results (to emulate local variables):
@@ -696,11 +696,11 @@ keymap during active completions (`company-active-map'):
 
 (defun company--multi-backend-adapter (backends command &rest args)
   (case command
-    ('candidates
+    (candidates
      (apply 'append (mapcar (lambda (backend) (apply backend command args))
                             backends)))
-    ('sorted nil)
-    ('duplicates t)
+    (sorted nil)
+    (duplicates t)
     (otherwise
      (let (value)
        (dolist (backend backends)
@@ -1801,8 +1801,8 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defun company-pseudo-tooltip-frontend (command)
   "A `company-mode' front-end similar to a tool-tip but based on overlays."
   (case command
-    ('pre-command (company-pseudo-tooltip-hide-temporarily))
-    ('post-command
+    (pre-command (company-pseudo-tooltip-hide-temporarily))
+    (post-command
      (let ((old-height (if (overlayp company-pseudo-tooltip-overlay)
                            (overlay-get company-pseudo-tooltip-overlay
                                         'company-height)
@@ -1814,11 +1814,11 @@ Returns a negative number if the tooltip should be 
displayed above point."
          (company-pseudo-tooltip-show-at-point (- (point)
                                                   (length company-prefix)))))
      (company-pseudo-tooltip-unhide))
-    ('hide (company-pseudo-tooltip-hide)
-           (setq company-tooltip-offset 0))
-    ('update (when (overlayp company-pseudo-tooltip-overlay)
-               (company-pseudo-tooltip-edit company-candidates
-                                            company-selection)))))
+    (hide (company-pseudo-tooltip-hide)
+          (setq company-tooltip-offset 0))
+    (update (when (overlayp company-pseudo-tooltip-overlay)
+              (company-pseudo-tooltip-edit company-candidates
+                                           company-selection)))))
 
 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
   "`company-pseudo-tooltip-frontend', but not shown for single candidates."
@@ -1866,9 +1866,9 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defun company-preview-frontend (command)
   "A `company-mode' front-end showing the selection as if it had been 
inserted."
   (case command
-    ('pre-command (company-preview-hide))
-    ('post-command (company-preview-show-at-point (point)))
-    ('hide (company-preview-hide))))
+    (pre-command (company-preview-hide))
+    (post-command (company-preview-show-at-point (point)))
+    (hide (company-preview-hide))))
 
 (defun company-preview-if-just-one-frontend (command)
   "`company-preview-frontend', but only shown for single candidates."
@@ -1966,20 +1966,20 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defun company-echo-frontend (command)
   "A `company-mode' front-end showing the candidates in the echo area."
   (case command
-    ('post-command (company-echo-show-soon 'company-echo-format))
-    ('hide (company-echo-hide))))
+    (post-command (company-echo-show-soon 'company-echo-format))
+    (hide (company-echo-hide))))
 
 (defun company-echo-strip-common-frontend (command)
   "A `company-mode' front-end showing the candidates in the echo area."
   (case command
-    ('post-command (company-echo-show-soon 'company-echo-strip-common-format))
-    ('hide (company-echo-hide))))
+    (post-command (company-echo-show-soon 'company-echo-strip-common-format))
+    (hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
   "A `company-mode' front-end showing the documentation in the echo area."
   (case command
-    ('post-command (company-echo-show-when-idle 'company-fetch-metadata))
-    ('hide (company-echo-hide))))
+    (post-command (company-echo-show-when-idle 'company-fetch-metadata))
+    (hide (company-echo-hide))))
 
 ;; templates 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 025de12a634e0430d0ff21a6c33a42ba58abaef0
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jun 18 14:48:24 2011 +0200

    Added compatibility info for Emacs 24.

diff --git a/company.el b/company.el
index b30bc8f..4641ab9 100644
--- a/company.el
+++ b/company.el
@@ -6,7 +6,7 @@
 ;; Version: 0.5
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://nschum.de/src/emacs/company/
-;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
+;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
 ;;
 ;; This file is NOT part of GNU Emacs.
 ;;

commit 320db73bb97dd7e0bb3f50a1ac9273d18eea01a4
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jun 18 14:47:38 2011 +0200

    Defined code style in .dir-locals.el file.

diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..a4fea85
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,2 @@
+((nil . ((indent-tabs-mode . nil)
+         (fill-column . 80))))

commit e1bee6aca61e5501bc46653d9ca7ba98efbad980
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 13:09:01 2010 +0100

    Fix error on already completed candidates.
    
    Even though company-common was t, company-candidates was set to non-nil
    again.

diff --git a/company.el b/company.el
index 0c0aacb..b30bc8f 100644
--- a/company.el
+++ b/company.el
@@ -1038,9 +1038,8 @@ can retrieve meta-data for them."
         (return c)))))
 
 (defun company-begin ()
-  (setq company-candidates
-        (or (and company-candidates (company--continue))
-            (and (company--should-complete) (company--begin-new))))
+  (or (and company-candidates (company--continue))
+      (and (company--should-complete) (company--begin-new)))
   (when company-candidates
     (when (and company-end-of-buffer-workaround (eobp))
       (save-excursion (insert "\n"))

commit 1f8413fb30d6c429d283c20f232c0ed73e12a542
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 11:45:47 2010 +0100

    Observe case in clang completions.

diff --git a/company-clang.el b/company-clang.el
index 5aaaa1d..f4725c7 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -101,6 +101,7 @@ Prefix files (-include ...) can be selected with
   (goto-char (point-min))
   (let ((pattern (format company-clang--completion-pattern
                          (regexp-quote prefix)))
+        (case-fold-search nil)
         lines match)
     (while (re-search-forward pattern nil t)
       (setq match (match-string-no-properties 1))

commit c98ad94fea089a3a0a0dd339752dd817a63c545f
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 11:45:10 2010 +0100

    Include macros in clang completions.

diff --git a/company-clang.el b/company-clang.el
index b054599..5aaaa1d 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -145,7 +145,7 @@ Prefix files (-include ...) can be selected with
             (1+ (current-column)))))
 
 (defsubst company-clang--build-complete-args (pos)
-  (append '("-cc1" "-fsyntax-only")
+  (append '("-cc1" "-fsyntax-only" "-code-completion-macros")
           company-clang-arguments
           (when (stringp company-clang--prefix)
             (list "-include" (expand-file-name company-clang--prefix)))

commit 0897957beade15f9224066c015da1b9a2dbb1fb9
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 00:55:11 2010 +0100

    New method for preventing echo display on busy machines.

diff --git a/company.el b/company.el
index 0eb220f..0c0aacb 100644
--- a/company.el
+++ b/company.el
@@ -1882,10 +1882,6 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defvar company-echo-last-msg nil)
 (make-variable-buffer-local 'company-echo-last-msg)
 
-(defvar company-echo-timer nil)
-
-(defvar company-echo-delay .01)
-
 (defun company-echo-show (&optional getter)
   (when getter
     (setq company-echo-last-msg (funcall getter)))
@@ -1897,8 +1893,16 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defsubst company-echo-show-soon (&optional getter)
   (when company-echo-timer
     (cancel-timer company-echo-timer))
-  (setq company-echo-timer (run-with-timer company-echo-delay nil
-                                           'company-echo-show getter)))
+  (setq company-echo-timer (run-with-timer 0 nil 'company-echo-show getter)))
+
+(defsubst company-echo-show-when-idle (&optional getter)
+  (when (sit-for .01)
+    (company-echo-show getter)))
+
+(defsubst company-echo-show-when-not-busy (&optional getter)
+  "Run `company-echo-show' with arg GETTER once Emacs isn't busy."
+  (when (sit-for company-echo-delay)
+    (company-echo-show getter)))
 
 (defun company-echo-format ()
 
@@ -1956,8 +1960,6 @@ Returns a negative number if the tooltip should be 
displayed above point."
             "}")))
 
 (defun company-echo-hide ()
-  (when company-echo-timer
-    (cancel-timer company-echo-timer))
   (unless (equal company-echo-last-msg "")
     (setq company-echo-last-msg "")
     (company-echo-show)))
@@ -1965,22 +1967,19 @@ Returns a negative number if the tooltip should be 
displayed above point."
 (defun company-echo-frontend (command)
   "A `company-mode' front-end showing the candidates in the echo area."
   (case command
-    ('pre-command (company-echo-show-soon))
     ('post-command (company-echo-show-soon 'company-echo-format))
     ('hide (company-echo-hide))))
 
 (defun company-echo-strip-common-frontend (command)
   "A `company-mode' front-end showing the candidates in the echo area."
   (case command
-    ('pre-command (company-echo-show-soon))
     ('post-command (company-echo-show-soon 'company-echo-strip-common-format))
     ('hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
   "A `company-mode' front-end showing the documentation in the echo area."
   (case command
-    ('pre-command (company-echo-show-soon))
-    ('post-command (company-echo-show-soon 'company-fetch-metadata))
+    ('post-command (company-echo-show-when-idle 'company-fetch-metadata))
     ('hide (company-echo-hide))))
 
 ;; templates 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

commit 3ec9528c6c8fe05f4d2bfe9522a513f1b5865596
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 17:33:06 2010 +0100

    Cleaned up company-etags.

diff --git a/company-etags.el b/company-etags.el
index 6683d44..55842d2 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -18,8 +18,7 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(eval-when-compile (require 'etags))
-(eval-when-compile (require 'cl))
+(require 'etags)
 
 (defcustom company-etags-use-main-table-list t
   "*Always search `tags-table-list' if set.
@@ -48,6 +47,15 @@ buffer automatically."
           (setq company-etags-buffer-table (company-etags-find-table))
         company-etags-buffer-table)))
 
+(defun company-etags--candidates (prefix)
+  (let ((tags-table-list (company-etags-buffer-table))
+        (completion-ignore-case nil))
+    (and (or tags-file-name tags-table-list)
+         (fboundp 'tags-completion-table)
+         (save-excursion
+           (visit-tags-table-buffer)
+           (all-completions prefix (tags-completion-table))))))
+
 ;;;###autoload
 (defun company-etags (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for etags."
@@ -56,17 +64,9 @@ buffer automatically."
     ('interactive (company-begin-backend 'company-etags))
     ('prefix (and (memq major-mode company-etags-modes)
                   (not (company-in-string-or-comment))
-                  (require 'etags nil t)
                   (company-etags-buffer-table)
                   (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((tags-table-list (company-etags-buffer-table))
-                       (completion-ignore-case nil))
-                   (and (or tags-file-name tags-table-list)
-                        (fboundp 'tags-completion-table)
-                        tags-table-list
-                        (save-excursion
-                          (visit-tags-table-buffer)
-                          (all-completions arg (tags-completion-table))))))
+    ('candidates (company-etags--candidates arg))
     ('location (let ((tags-table-list (company-etags-buffer-table)))
                  (when (fboundp 'find-tag-noselect)
                    (save-excursion

commit bb7820c65daaae6ec260f6f6b884f0d4dc5fd98f
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 27 17:22:09 2010 +0100

    Fix tag file switching in company-etags.

diff --git a/company-etags.el b/company-etags.el
index eeb7d90..6683d44 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -64,7 +64,9 @@ buffer automatically."
                    (and (or tags-file-name tags-table-list)
                         (fboundp 'tags-completion-table)
                         tags-table-list
-                        (all-completions arg (tags-completion-table)))))
+                        (save-excursion
+                          (visit-tags-table-buffer)
+                          (all-completions arg (tags-completion-table))))))
     ('location (let ((tags-table-list (company-etags-buffer-table)))
                  (when (fboundp 'find-tag-noselect)
                    (save-excursion
diff --git a/company.el b/company.el
index d22dfd5..0eb220f 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Switching tags now works correctly in `company-etags'.
+;;
 ;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
 ;;    Added `company-with-candidate-inserted' macro.

commit 7d0348f081468e6af68879721190da7996e09c6e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jun 18 14:14:50 2011 +0200

    Moved tests to ERT.

diff --git a/company-tests.el b/company-tests.el
new file mode 100644
index 0000000..bb1e654
--- /dev/null
+++ b/company-tests.el
@@ -0,0 +1,13 @@
+(require 'ert)
+(require 'company)
+(require 'company-keywords)
+
+(ert-deftest sorted-keywords ()
+  "Test that keywords in `company-keywords-alist' are in alphabetical order."
+  (dolist (pair company-keywords-alist)
+    (when (consp (cdr pair))
+      (let ((prev (cadr pair)))
+        (dolist (next (cddr pair))
+          (should (not (equal prev next)))
+          (should (string< prev next))
+          (setq prev next))))))
diff --git a/tests.elk b/tests.elk
deleted file mode 100644
index 0d9288b..0000000
--- a/tests.elk
+++ /dev/null
@@ -1,11 +0,0 @@
-(require 'elk-test)
-
-(deftest "Sorted keywords"
-  (require 'company-keywords)
-  (dolist (pair company-keywords-alist)
-    (when (consp (cdr pair))
-      (let ((prev (cadr pair)))
-        (dolist (next (cddr pair))
-          (assert-not-equal prev next)
-          (assert-string< prev next)
-          (setq prev next))))))

commit 7623164a088658b1546d94f2574973986b13f540
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jun 16 22:00:50 2011 +0200

    (ioccur): use pop-to-buffer for compatibility with new emacs24 window.el.

diff --git a/ioccur.el b/ioccur.el
index 96e7a83..f2ff024 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -961,7 +961,8 @@ for commands provided in the `ioccur-buffer'."
              str-no-prop)
         (set-text-properties 0 len nil init-str)
         (setq str-no-prop init-str)
-        (switch-to-buffer-other-window (get-buffer-create ioccur-buffer) t)
+        ;(switch-to-buffer-other-window (get-buffer-create ioccur-buffer) t)
+        (pop-to-buffer (get-buffer-create ioccur-buffer))
         (ioccur-mode)
         (unwind-protect
              ;; Start incremental search.

commit 702d282b579924d5d5a250f019fc2cce01ebca05
Merge: c7f4d2c b576997
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jun 10 06:53:53 2011 +0200

    merge branchs


commit b57699722f35f8bdedc63e634a4a72e5da87a4e9
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jun 10 06:50:37 2011 +0200

    (ioccur): Turn buffer read-only.

diff --git a/ioccur.el b/ioccur.el
index de4d43b..96e7a83 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -950,6 +950,7 @@ for commands provided in the `ioccur-buffer'."
                            ""))
              (len      (length init-str))
              (curpos   (point))
+             (inhibit-read-only t)
              (cur-mode (with-current-buffer ioccur-current-buffer
                          (prog1
                              major-mode
@@ -990,7 +991,10 @@ for commands provided in the `ioccur-buffer'."
                    (kill-buffer ioccur-buffer)
                    (ioccur-send-message) (ioccur-save-history))
                   (t                   ; Jump keeping `ioccur-buffer'.
-                   (ioccur-jump) (pop-to-buffer ioccur-buffer) 
(ioccur-save-history)))
+                   (ioccur-jump)
+                   (pop-to-buffer ioccur-buffer)
+                   (setq buffer-read-only t)
+                   (ioccur-save-history)))
             ;; Maybe reenable `wdired-mode'.
             (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
             (setq ioccur-count-occurences 0)

commit 74a91351d1f4f68526bfdb40fb0f34d4fd12e7bf
Author: Alexander Solovyov <address@hidden>
Date:   Sun Jun 5 15:30:40 2011 +0200

    do not leave trailing whitespaces on newline

diff --git a/coffee-mode.el b/coffee-mode.el
index f3d875e..6e68384 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -485,6 +485,7 @@ For detail, see `comment-dwim'."
   ;; insert a newline, and indent the newline to the same
   ;; level as the previous line.
   (let ((prev-indent (current-indentation)) (indent-next nil))
+    (delete-horizontal-space t)
     (newline)
     (insert-tab (/ prev-indent coffee-tab-width))
 

commit 37b481e4a33732d84388f16bbe64e2d795cbf960
Author: Chris Wanstrath <address@hidden>
Date:   Mon Jun 6 18:28:00 2011 +0200

    Better assignment highlighting for `:`
    
    These now highlight as expected:
    
    key: value
    key : value
    
    new Thing key: value

diff --git a/coffee-mode.el b/coffee-mode.el
index 6ae08a5..f3d875e 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -238,7 +238,7 @@ path."
 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| 
\\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
 ;; Assignment
-(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
+(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\|$\\)+?\s*\\):")
 
 ;; Lambda
 (defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")

commit c7f4d2c4dc5afeb5554832c415c0cfd5b84377c4
Merge: ccf74d2 cc9b329
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jun 4 15:20:20 2011 +0200

    merge branchs


commit ccf74d286a90f636ce9433bc1aedeb3f07cac0e9
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 31 06:57:35 2011 +0200

    (ioccur-jump, *-without-quit):fix markers.

diff --git a/ioccur.el b/ioccur.el
index 618b316..de4d43b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -557,7 +557,8 @@ Move point to first occurence of `ioccur-pattern'."
       (if win-conf
           (set-window-configuration win-conf)
           (pop-to-buffer ioccur-current-buffer))
-      (ioccur-goto-line pos) (recenter) (set-marker (mark-marker) (point))
+      (ioccur-goto-line pos)
+      (recenter)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-pattern'.
       (when (funcall ioccur-search-function
@@ -579,7 +580,8 @@ Move point to first occurence of `ioccur-pattern'."
   "Jump to line in `ioccur-current-buffer' without quitting."
   (interactive)
   (when (ioccur-jump ioccur-last-window-configuration)
-    (when mark (push-mark (point) 'nomsg))
+    (and mark (set-marker (mark-marker) (point))
+         (push-mark (point) 'nomsg))
     (switch-to-buffer-other-window ioccur-buffer t)))
 
 ;;;###autoload

commit c46609c148ea78f11e4ae68feacc8dc157dabe74
Author: Chris Wanstrath <address@hidden>
Date:   Wed May 25 13:59:50 2011 -0700

    no-wrap => bare in README

diff --git a/README.md b/README.md
index 095c9e9..d0a4d77 100644
--- a/README.md
+++ b/README.md
@@ -203,7 +203,7 @@ Naturally. Example:
       (setq coffee-js-mode 'javascript-mode)
 
       ;; If you don't want your compiled files to be wrapped
-      (setq coffee-args-compile '("-c" "--no-wrap"))
+      (setq coffee-args-compile '("-c" "--bare"))
 
       ;; *Messages* spam
       (setq coffee-debug-mode t)

commit 6eb6d992deb91e0cd73bfe7ab374d2720d224891
Author: Akinori MUSHA <address@hidden>
Date:   Wed May 25 00:23:41 2011 +0900

    Introduce a minor mode `coffee-cos-mode'.

diff --git a/coffee-mode.el b/coffee-mode.el
index 6ae08a5..dab1446 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -573,6 +573,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   (define-key coffee-mode-map (kbd "A-M-r") 'coffee-repl)
   (define-key coffee-mode-map [remap comment-dwim] 'coffee-comment-dwim)
   (define-key coffee-mode-map "\C-m" 'coffee-newline-and-indent)
+  (define-key coffee-mode-map "\C-c\C-o\C-s" 'coffee-cos-mode)
 
   ;; code for syntax highlighting
   (setq font-lock-defaults '((coffee-font-lock-keywords)))
@@ -600,6 +601,22 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; hooks
   (set (make-local-variable 'before-save-hook) 'coffee-before-save))
 
+;;
+;; Compile-on-Save minor mode
+;;
+
+(defvar coffee-cos-mode-line " CoS")
+(make-variable-buffer-local 'coffee-cos-mode-line)
+
+(define-minor-mode coffee-cos-mode
+  "Toggle compile-on-save for coffee-mode."
+  :group 'coffee-cos :lighter coffee-cos-mode-line
+  (cond
+   (coffee-cos-mode
+    (add-hook 'after-save-hook 'coffee-compile-file nil t))
+   (t
+    (remove-hook 'after-save-hook 'coffee-compile-file t))))
+
 (provide 'coffee-mode)
 
 ;;

commit bca81b6e9bc4299be94bc1009fb495ec0b09bdad
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 24 14:35:24 2011 +0200

    (ioccur-save-history): Bugfix, typo replace anything-pattern ==> 
ioccur-pattern.

diff --git a/ioccur.el b/ioccur.el
index e6e9306..618b316 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -998,12 +998,12 @@ for commands provided in the `ioccur-buffer'."
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."
-  (unless (string= anything-pattern "")
+  (unless (string= ioccur-pattern "")
     (setq ioccur-history
           (cons ioccur-pattern (delete ioccur-pattern ioccur-history)))
     (when (> (length ioccur-history) ioccur-max-length-history)
       (setq ioccur-history (delete (car (last ioccur-history))
-                                   ioccur-history)))
+                                         ioccur-history)))
     (setq ioccur-success t)))
 
 (defun ioccur-cancel-search ()

commit 5e1094e513013b534777c65ac4b08049c63ee45a
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 24 14:10:45 2011 +0200

    (ioccur-print-line): Fix highlighting long truncated lines (e.g when using 
^.\{81\}).

diff --git a/ioccur.el b/ioccur.el
index ae7804a..e6e9306 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -328,6 +328,7 @@ If ALL is non--nil highlight the whole string STR."
              (point) (point-at-eol)
              '(face ioccur-match-face))  
             (while (and (funcall ioccur-search-function ioccur-pattern nil t)
+                        ;; Don't try to highlight line with a length <= 0.
                         (> (- (match-end 0) (match-beginning 0)) 0))
               (add-text-properties
                (match-beginning 0) (match-end 0)
@@ -340,11 +341,12 @@ If ALL is non--nil highlight the whole string STR."
   (with-current-buffer ioccur-buffer
     (let* ((lineno             (int-to-string (1+ nline)))
            (whole-line-matched (string= match line))
-           (trunc-line         (if ioccur-highlight-match-p
+           (hightline          (if ioccur-highlight-match-p
                                    (ioccur-print-match
-                                    (ioccur-truncate-line line)
+                                    line
                                     whole-line-matched)
-                                   (ioccur-truncate-line line))))
+                                   line))
+           (trunc-line          (ioccur-truncate-line hightline)))
       (incf ioccur-count-occurences)
       (insert " " (propertize lineno 'face 'ioccur-num-line-face
                               'help-echo line)

commit ad93c34c1efd0217e502a7491e1f8c4a01c33d16
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 24 10:16:47 2011 +0200

    (ioccur-highlight-match-on-line): Remove no more used.

diff --git a/ioccur.el b/ioccur.el
index 95daa50..ae7804a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -350,18 +350,6 @@ If ALL is non--nil highlight the whole string STR."
                               'help-echo line)
               ":" trunc-line "\n"))))
 
-(defun ioccur-highlight-match-on-line (regexp)
-  "Highlight all occurences of REGEXP on precedent line."
-  (save-excursion
-    (forward-line -1) (re-search-forward "\\(\\s-[0-9]+:\\)" nil t)
-    (while (and (funcall ioccur-search-function regexp (point-at-eol) t)
-                ;; If length of match is null exit loop.
-                ;; e.g when searching "^".
-                (> (- (match-end 0) (match-beginning 0)) 0))
-      (put-text-property (match-beginning 0) (match-end 0); (point)
-                         'face 'ioccur-match-face))))
-
-
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
   "Remove indentation in LINE and truncate modified LINE of num COLUMNS.
 COLUMNS default value is `ioccur-length-line'.

commit a9e79afce7316e195df9c47781515650dfe80651
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 24 09:02:07 2011 +0200

    (ioccur-print-match): Forget to change face name.

diff --git a/ioccur.el b/ioccur.el
index a4c9e94..95daa50 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -326,7 +326,7 @@ If ALL is non--nil highlight the whole string STR."
         (if all
             (add-text-properties
              (point) (point-at-eol)
-             '(face anything-grep-match))  
+             '(face ioccur-match-face))  
             (while (and (funcall ioccur-search-function ioccur-pattern nil t)
                         (> (- (match-end 0) (match-beginning 0)) 0))
               (add-text-properties

commit ef54e782c09969b7839d06f99274c5dd74828ae5
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 24 08:56:02 2011 +0200

    (ioccur-print-line): Bugfix in highlight match.
    (ioccur-print-match): new use it.

diff --git a/ioccur.el b/ioccur.el
index 5787163..a4c9e94 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -315,23 +315,40 @@ Special commands:
              count (match-string 0) regexp)
          do (forward-line 1)))))
 
+
+(defun ioccur-print-match (str &optional all)
+  "Highlight in string STR all occurences matching `ioccur-pattern'.
+If ALL is non--nil highlight the whole string STR."
+  (condition-case nil
+      (with-temp-buffer
+        (insert str)
+        (goto-char (point-min))
+        (if all
+            (add-text-properties
+             (point) (point-at-eol)
+             '(face anything-grep-match))  
+            (while (and (funcall ioccur-search-function ioccur-pattern nil t)
+                        (> (- (match-end 0) (match-beginning 0)) 0))
+              (add-text-properties
+               (match-beginning 0) (match-end 0)
+               '(face ioccur-match-face))))
+        (buffer-string))
+    (error nil)))
+
 (defun ioccur-print-line (line nline match regexp)
   "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let* ((lineno             (int-to-string (1+ nline)))
-           (trunc-line         (ioccur-truncate-line line))
-           (whole-line-matched (string= match line)))
+           (whole-line-matched (string= match line))
+           (trunc-line         (if ioccur-highlight-match-p
+                                   (ioccur-print-match
+                                    (ioccur-truncate-line line)
+                                    whole-line-matched)
+                                   (ioccur-truncate-line line))))
       (incf ioccur-count-occurences)
       (insert " " (propertize lineno 'face 'ioccur-num-line-face
                               'help-echo line)
-              ":" trunc-line "\n")
-      (when ioccur-highlight-match-p
-        (if whole-line-matched ; Regexp match the whole line, highlight it.
-            (save-excursion
-              (forward-line -1) (re-search-forward "\\(\\s-[0-9]+:\\)" nil t)
-              (put-text-property (point) (point-at-eol)
-                                 'face 'ioccur-match-face))
-            (ioccur-highlight-match-on-line regexp))))))
+              ":" trunc-line "\n"))))
 
 (defun ioccur-highlight-match-on-line (regexp)
   "Highlight all occurences of REGEXP on precedent line."
@@ -341,7 +358,7 @@ Special commands:
                 ;; If length of match is null exit loop.
                 ;; e.g when searching "^".
                 (> (- (match-end 0) (match-beginning 0)) 0))
-      (put-text-property (match-beginning 0) (point)
+      (put-text-property (match-beginning 0) (match-end 0); (point)
                          'face 'ioccur-match-face))))
 
 

commit 1c093534670e89d8e6487e9c63c0199e47311a6f
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 18 12:11:38 2011 +0200

    (ioccur-save-history): Don't save when pattern is empty.

diff --git a/ioccur.el b/ioccur.el
index 2059f27..5787163 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -991,12 +991,13 @@ for commands provided in the `ioccur-buffer'."
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."
-  (setq ioccur-history
-        (cons ioccur-pattern (delete ioccur-pattern ioccur-history)))
-  (when (> (length ioccur-history) ioccur-max-length-history)
-    (setq ioccur-history (delete (car (last ioccur-history))
-                                 ioccur-history)))
-  (setq ioccur-success t))
+  (unless (string= anything-pattern "")
+    (setq ioccur-history
+          (cons ioccur-pattern (delete ioccur-pattern ioccur-history)))
+    (when (> (length ioccur-history) ioccur-max-length-history)
+      (setq ioccur-history (delete (car (last ioccur-history))
+                                   ioccur-history)))
+    (setq ioccur-success t)))
 
 (defun ioccur-cancel-search ()
   "Cancel timer used for ioccur searching."

commit 4eaefad860ee6596eadeb817d8a962e2926d3649
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 18 11:56:21 2011 +0200

    (ioccur-save-history): Simplify.

diff --git a/ioccur.el b/ioccur.el
index ec68616..2059f27 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -991,19 +991,8 @@ for commands provided in the `ioccur-buffer'."
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."
-  ;; Push elm in history if not already there or empty.
-  (unless (or (member ioccur-pattern ioccur-history)
-              (string= ioccur-pattern ""))
-    (push ioccur-pattern ioccur-history))
-  ;; If elm already exists in history ring
-  ;; push it on top of stack.
-  (let ((pos-hist-elm (ioccur-position
-                       ioccur-pattern
-                       ioccur-history :test 'equal)))
-    (unless (string= (car ioccur-history)
-                     ioccur-pattern)
-      (push (pop (nthcdr pos-hist-elm ioccur-history))
-            ioccur-history)))
+  (setq ioccur-history
+        (cons ioccur-pattern (delete ioccur-pattern ioccur-history)))
   (when (> (length ioccur-history) ioccur-max-length-history)
     (setq ioccur-history (delete (car (last ioccur-history))
                                  ioccur-history)))

commit c8a76fb8777b8007e35bf34c23af95234387fd7e
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 5 19:16:49 2011 +0400

    Mark indentation vars as safe file-local variables
    
    Fixes http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=607110

diff --git a/js2-mode.el b/js2-mode.el
index 0690647..f94395d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -172,6 +172,12 @@ Set `js2-include-gears-externs' to t to include them.")
 
 ;;; Variables
 
+(defun js2-mark-safe-local (name pred)
+  "Make the variable NAME buffer-local and mark it as safe file-local
+variable with predicate PRED."
+  (make-variable-buffer-local name)
+  (put name 'safe-local-variable pred))
+
 (defvar js2-emacs22 (>= emacs-major-version 22))
 
 (defcustom js2-highlight-level 2
@@ -201,7 +207,7 @@ Set `js2-include-gears-externs' to t to include them.")
 Similar to `c-basic-offset'."
   :group 'js2-mode
   :type 'integer)
-(make-variable-buffer-local 'js2-basic-offset)
+(js2-mark-safe-local 'js2-basic-offset 'integerp)
 
 ;; TODO(stevey):  move this code into a separate minor mode.
 (defcustom js2-mirror-mode nil
@@ -233,12 +239,14 @@ js2-mode also binds `js2-bounce-indent-backwards' to 
Shift-Tab."
 regardless of the beginning bracket position."
   :group 'js2-mode
   :type 'boolean)
+(js2-mark-safe-local 'js2-consistent-level-indent-inner-bracket-p 'booleanp)
 
 (defcustom js2-pretty-multiline-decl-indentation-p t
   "Non-nil to line up multiline declarations vertically. See the
 function `js-multiline-decl-indentation' for details."
   :group 'js2-mode
   :type 'boolean)
+(js2-mark-safe-local 'js2-pretty-multiline-decl-indentation-p 'booleanp)
 
 (defcustom js2-always-indent-assigned-expr-in-decls-p nil
   "If both `js2-pretty-multiline-decl-indentation-p' and this are non-nil,
@@ -246,6 +254,7 @@ always additionally indent function expression or 
array/object literal
 assigned in a declaration, even when only one var is declared."
   :group 'js2-mode
   :type 'boolean)
+(js2-mark-safe-local 'js2-always-indent-assigned-expr-in-decls-p 'booleanp)
 
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.

commit 719d497f91e21d5bd80b120474b923751a55e4e3
Author: Dmitry Gutov <address@hidden>
Date:   Thu May 5 03:01:36 2011 +0400

    Properly record function qnames in object literals
    
    This fixes imenu index for quux and baz:
    
    let foo = {
      bar: function() {
        function quux() {
          // ...
        }
    
        let oot = {
          baz: function() {},
        }
      }
    }

diff --git a/js2-mode.el b/js2-mode.el
index 70c3886..0690647 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6846,7 +6846,7 @@ POS is the absolute position of the node.
 We do a depth-first traversal of NODE.  Any functions we find are prefixed
 with QNAME plus the property name of the function and appended to the
 variable `js2-imenu-recorder'."
-  (let (left right)
+  (let (left right prop-qname)
     (dolist (e (js2-object-node-elems node))  ; e is a `js2-object-prop-node'
       (let ((left (js2-infix-node-left e))
             ;; Element positions are relative to the parent position.
@@ -6858,9 +6858,9 @@ variable `js2-imenu-recorder'."
             ;; As a policy decision, we record the position of the property,
             ;; not the position of the `function' keyword, since the property
             ;; is effectively the name of the function.
-            (push (append qname (list left pos))
+            (push (setq prop-qname (append qname (list left pos)))
                   js2-imenu-recorder)
-            (js2-record-function-qname right qname)))
+            (js2-record-function-qname right prop-qname)))
          ;; foo: {object-literal} -- add foo to qname, offset position, and 
recurse
          ((js2-object-node-p right)
           (js2-record-object-literal right

commit 3c15500bb84dcc5a31814b7f53757b461b583280
Author: Dmitry Gutov <address@hidden>
Date:   Tue May 3 00:25:06 2011 +0400

    Handle the case when the reparse is scheduled in an inactive buffer
    
    Fixes http://code.google.com/p/js2-mode/issues/detail?id=69

diff --git a/js2-mode.el b/js2-mode.el
index 5d162a2..70c3886 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10522,7 +10522,25 @@ You can disable this by customizing 
`js2-cleanup-whitespace'."
       (cancel-timer js2-mode-parse-timer))
   (setq js2-mode-parsing nil)
   (setq js2-mode-parse-timer
-        (run-with-idle-timer js2-idle-timer-delay nil #'js2-reparse)))
+        (run-with-idle-timer js2-idle-timer-delay nil
+                             #'js2-mode-idle-reparse (current-buffer))))
+
+(defun js2-mode-idle-reparse (buffer)
+  "Run `js2-reparse' if BUFFER is the current buffer, or schedule
+it to be reparsed when the buffer is selected."
+  (if (eq buffer (current-buffer))
+      (js2-reparse)
+    ;; reparse when the buffer is selected again
+    (with-current-buffer buffer
+      (add-hook 'window-configuration-change-hook
+                #'js2-mode-idle-reparse-inner
+                t))))
+
+(defun js2-mode-idle-reparse-inner ()
+  (remove-hook 'window-configuration-change-hook
+               #'js2-mode-idle-reparse-inner
+               t)
+  (js2-reparse))
 
 (defun js2-mode-edit (beg end len)
   "Schedule a new parse after buffer is edited.

commit 688ed47c27ab0973ac6adb255c10595676775963
Author: Dmitry Gutov <address@hidden>
Date:   Fri Apr 29 04:35:43 2011 +0400

    Close #11 indent-for-tab-command: jump to indentation when inside it

diff --git a/js2-mode.el b/js2-mode.el
index 66d10f6..5d162a2 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9938,7 +9938,7 @@ var o = {                               var bar = 2,
         (when (looking-at js-indent-operator-re)
           (goto-char (match-end 0))) ; continued expressions are ok
         (while (and (not at-opening-bracket)
-                    (not (= (point) (point-min)))
+                    (not (bobp))
                     (let ((pos (point)))
                       (save-excursion
                         (js2-backward-sws)
@@ -10356,7 +10356,6 @@ If so, we don't ever want to use bounce-indent."
   "Indent the current line as JavaScript source text."
   (interactive)
   (let (parse-status
-        current-indent
         offset
         indent-col
         moved
@@ -10367,28 +10366,23 @@ If so, we don't ever want to use bounce-indent."
                           (syntax-ppss (point-at-bol)))
           offset (- (point) (save-excursion
                                (back-to-indentation)
-                               (setq current-indent (current-column))
                                (point))))
     (js2-with-underscore-as-word-syntax
      (if (nth 4 parse-status)
          (js2-lineup-comment parse-status)
        (setq indent-col (js-proper-indentation parse-status))
        ;; see comments below about js2-mode-last-indented-line
-       (when
-           (cond
-            ;; bounce-indenting is disabled during electric-key indent.
-            ;; It doesn't work well on first line of buffer.
-            ((and js2-bounce-indent-p
-                  (not (js2-same-line (point-min)))
-                  (not (js2-1-line-comment-continuation-p)))
-             (js2-bounce-indent indent-col parse-status bounce-backwards)
-             (setq moved t))
-            ;; just indent to the guesser's likely spot
-            ((/= current-indent indent-col)
-             (indent-line-to indent-col)
-             (setq moved t)))
-         (when (and moved (plusp offset))
-           (forward-char offset)))))))
+       (cond
+        ;; bounce-indenting is disabled during electric-key indent.
+        ;; It doesn't work well on first line of buffer.
+        ((and js2-bounce-indent-p
+              (not (js2-same-line (point-min)))
+              (not (js2-1-line-comment-continuation-p)))
+         (js2-bounce-indent indent-col parse-status bounce-backwards))
+        ;; just indent to the guesser's likely spot
+        (t (indent-line-to indent-col)))
+       (when (plusp offset)
+         (forward-char offset))))))
 
 (defun js2-indent-region (start end)
   "Indent the region, but don't use bounce indenting."

commit a9ff661cd98bb7523bc04ca88270d64ef1d00620
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 27 23:09:19 2011 +0400

    Indent continued expressions in multiline declarations better
    
    let a = 5 + 3,
        b = "booo" + "bar"
          + "toot" + "tar";
    
    This change also makes `js2-auto-indent-p' less useful: each new line
    in a declaration is automatically indented.

diff --git a/js2-mode.el b/js2-mode.el
index b4cf4ed..66d10f6 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9914,7 +9914,7 @@ indented to the same column as the current line."
                     (= (current-indentation) saved-indent)))))))))
 
 (defun js-multiline-decl-indentation ()
-  "Returns the proper indentation of the current line if it belongs
+  "Returns the declaration indentation column if the current line belongs
 to a multiline declaration statement.  All declarations are lined up 
vertically:
 
 var a = 10,
@@ -9934,22 +9934,22 @@ var o = {                               var bar = 2,
         at-opening-bracket)
     (save-excursion
       (back-to-indentation)
-      (when (and (not (looking-at js-declaration-keyword-re))
-                 (looking-at (concat js2-mode-identifier-re
-                                     "[ \t]*\\(?:=[^=]\\|\\,\\|;\\|$\\)")))
-        (while (not (save-excursion
-                      ;; unary ops
-                      (skip-chars-backward "-+~! \t")
-                      (or at-opening-bracket
-                          ;; explicit semicolon
-                          (save-excursion (js2-backward-sws)
-                                          (eq (char-before) ?\;))
-                          ;; implicit semicolon
-                          (and (bolp)
-                               (progn (js2-backward-sws)
-                                      (not (eq (char-before) ?,)))
-                               (progn (skip-chars-backward "[[:punct:]]")
-                                      (not (looking-at 
js-indent-operator-re)))))))
+      (when (not (looking-at js-declaration-keyword-re))
+        (when (looking-at js-indent-operator-re)
+          (goto-char (match-end 0))) ; continued expressions are ok
+        (while (and (not at-opening-bracket)
+                    (not (= (point) (point-min)))
+                    (let ((pos (point)))
+                      (save-excursion
+                        (js2-backward-sws)
+                        (or (eq (char-before) ?,)
+                            (and (not (eq (char-before) ?\;))
+                                 (and
+                                  (prog2 (skip-chars-backward "[[:punct:]]")
+                                      (looking-at js-indent-operator-re)
+                                    (js2-backward-sws))
+                                  (not (eq (char-before) ?\;))))
+                            (js2-same-line pos)))))
           (condition-case err
               (backward-sexp)
             (scan-error (setq at-opening-bracket t))))
@@ -10038,8 +10038,11 @@ In particular, return the buffer position of the first 
`for' kwd."
 
        (ctrl-stmt-indent)
 
-       (declaration-indent)
+       ((and declaration-indent continued-expr-p)
+        (+ declaration-indent js2-basic-offset))
        
+       (declaration-indent)
+
        (bracket
         (goto-char bracket)
         (cond

commit 5cd3b546f0827223b76cdf9c7ac99ca75a812d1d
Author: Dmitry Gutov <address@hidden>
Date:   Wed Apr 27 01:20:40 2011 +0400

    Fix indentation of empty array literals

diff --git a/js2-mode.el b/js2-mode.el
index e02a154..b4cf4ed 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9999,7 +9999,8 @@ In particular, return the buffer position of the first 
`for' kwd."
                     (match-beginning 0)))
             ;; to skip arbitrary expressions we need the parser,
             ;; so we'll just guess at it.
-            (if (re-search-forward "[^,]* \\(for\\) " end t)
+            (if (and (> end (point)) ; not empty literal
+                     (re-search-forward "[^,]]* \\(for\\) " end t))
                 (match-beginning 1))))))))
 
 (defun js2-array-comp-indentation (parse-status for-kwd)

commit 887ed13ccbb86dbc66e2f38e2db965f486b00038
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 26 03:57:36 2011 +0400

    Typo

diff --git a/js2-mode.el b/js2-mode.el
index 5f1e3bc..e02a154 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -242,7 +242,7 @@ function `js-multiline-decl-indentation' for details."
 
 (defcustom js2-always-indent-assigned-expr-in-decls-p nil
   "If both `js2-pretty-multiline-decl-indentation-p' and this are non-nil,
-always additionally indents function expression or array/object literal
+always additionally indent function expression or array/object literal
 assigned in a declaration, even when only one var is declared."
   :group 'js2-mode
   :type 'boolean)

commit f1397b34b87b118a76ebbe90bb7e55ef8cdc72d7
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 26 02:29:44 2011 +0400

    Improve `js-multiline-decl-indentation'
    
    * Top-level let/var/const form could be indented to infinity
    * Support declarations without assignment

diff --git a/js2-mode.el b/js2-mode.el
index 205cd25..5f1e3bc 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9934,18 +9934,20 @@ var o = {                               var bar = 2,
         at-opening-bracket)
     (save-excursion
       (back-to-indentation)
-      (when (looking-at (concat js2-mode-identifier-re "[ \t]*=[^=]"))
+      (when (and (not (looking-at js-declaration-keyword-re))
+                 (looking-at (concat js2-mode-identifier-re
+                                     "[ \t]*\\(?:=[^=]\\|\\,\\|;\\|$\\)")))
         (while (not (save-excursion
                       ;; unary ops
                       (skip-chars-backward "-+~! \t")
                       (or at-opening-bracket
                           ;; explicit semicolon
                           (save-excursion (js2-backward-sws)
-                                          (= (char-before) ?\;))
+                                          (eq (char-before) ?\;))
                           ;; implicit semicolon
                           (and (bolp)
                                (progn (js2-backward-sws)
-                                      (/= (char-before) ?,))
+                                      (not (eq (char-before) ?,)))
                                (progn (skip-chars-backward "[[:punct:]]")
                                       (not (looking-at 
js-indent-operator-re)))))))
           (condition-case err

commit a1688feb3e3b6c721a17c2f0d406a0a0285b1cb4
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 26 01:47:33 2011 +0400

    Close #3 Indent function/array/object values in declarations better

diff --git a/js2-mode.el b/js2-mode.el
index febb6d5..205cd25 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -240,6 +240,13 @@ function `js-multiline-decl-indentation' for details."
   :group 'js2-mode
   :type 'boolean)
 
+(defcustom js2-always-indent-assigned-expr-in-decls-p nil
+  "If both `js2-pretty-multiline-decl-indentation-p' and this are non-nil,
+always additionally indents function expression or array/object literal
+assigned in a declaration, even when only one var is declared."
+  :group 'js2-mode
+  :type 'boolean)
+
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.
 This is unusual for Emacs modes but common in IDEs like Eclipse."
@@ -9908,11 +9915,20 @@ indented to the same column as the current line."
 
 (defun js-multiline-decl-indentation ()
   "Returns the proper indentation of the current line if it belongs
-to a multiline declaration statement.  All assignments are lined up vertically:
+to a multiline declaration statement.  All declarations are lined up 
vertically:
 
 var a = 10,
     b = 20,
     c = 30;
+
+Note that if `js2-always-indent-assigned-expr-in-decls-p' is nil, and the first
+assigned expression is a function or array/object literal, it will be indented
+differently:
+
+var o = {                               var bar = 2,
+  foo: 3                                    o = {
+},                                            foo: 3
+    bar = 2;                                };
 "
   (let (forward-sexp-function ; use lisp version
         at-opening-bracket)
@@ -10033,7 +10049,11 @@ In particular, return the buffer position of the first 
`for' kwd."
                      (not js2-consistent-level-indent-inner-bracket-p))
                 (progn (goto-char (1+ (nth 1 p)))
                        (skip-chars-forward " \t"))
-              (back-to-indentation))
+              (back-to-indentation)
+              (when (and js2-pretty-multiline-decl-indentation-p
+                         js2-always-indent-assigned-expr-in-decls-p
+                         (looking-at js-declaration-keyword-re))
+                (goto-char (1+ (match-end 0)))))
             (cond (same-indent-p
                    (current-column))
                   (continued-expr-p

commit 8fd6d6703940898a426adfc8691dc392c462036f
Author: Dmitry Gutov <address@hidden>
Date:   Tue Apr 26 01:35:26 2011 +0400

    delq -> remq

diff --git a/js2-mode.el b/js2-mode.el
index 8788d91..febb6d5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10368,7 +10368,7 @@ If so, we don't ever want to use bounce-indent."
   "Indent the region, but don't use bounce indenting."
   (let ((js2-bounce-indent-p nil)
         (indent-region-function nil)
-        (after-change-functions (delq 'js2-mode-edit
+        (after-change-functions (remq 'js2-mode-edit
                                       after-change-functions)))
     (indent-region start end nil) ; nil for byte-compiler
     (js2-mode-edit start end (- end start))))

commit 100ee8e1bb54cbb89eac435906acaa4f857dcf22
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 25 18:49:58 2011 +0400

    Don't call `js2-mode-edit' when inside `indent-region'

diff --git a/js2-mode.el b/js2-mode.el
index 805e9c1..8788d91 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10367,8 +10367,11 @@ If so, we don't ever want to use bounce-indent."
 (defun js2-indent-region (start end)
   "Indent the region, but don't use bounce indenting."
   (let ((js2-bounce-indent-p nil)
-        (indent-region-function nil))
-    (indent-region start end nil)))  ; nil for byte-compiler
+        (indent-region-function nil)
+        (after-change-functions (delq 'js2-mode-edit
+                                      after-change-functions)))
+    (indent-region start end nil) ; nil for byte-compiler
+    (js2-mode-edit start end (- end start))))
 
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
 

commit e2f8fc6b7535f998731e1ec7f6020a782e92aaa7
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 25 17:53:37 2011 +0400

    `looking-back' is slow; don't use it when indenting

diff --git a/js2-mode.el b/js2-mode.el
index f0e7722..805e9c1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9925,11 +9925,11 @@ var a = 10,
                       (or at-opening-bracket
                           ;; explicit semicolon
                           (save-excursion (js2-backward-sws)
-                                          (looking-back ";"))
+                                          (= (char-before) ?\;))
                           ;; implicit semicolon
                           (and (bolp)
                                (progn (js2-backward-sws)
-                                      (not (looking-back ",")))
+                                      (/= (char-before) ?,))
                                (progn (skip-chars-backward "[[:punct:]]")
                                       (not (looking-at 
js-indent-operator-re)))))))
           (condition-case err
@@ -9951,7 +9951,7 @@ returns nil."
                  (not (looking-at "[{([]"))
                  (progn
                    (forward-char)
-                   (when (looking-back ")")
+                   (when (= (char-before) ?\))
                      ;; scan-sexps sometimes throws an error
                      (ignore-errors (backward-sexp))
                      (skip-chars-backward " \t" (point-at-bol)))

commit 1ef1ebea151f80a8ca32f8136f3edac032f694ab
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 25 17:46:26 2011 +0400

    Use `syntax-ppss' instead of `parse-partial-sexp' where appropriate

diff --git a/js2-mode.el b/js2-mode.el
index f4c1b1b..f0e7722 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9771,7 +9771,7 @@ bound to KEY in the global keymap and indents the current 
line."
         (call-interactively cmd)))
   ;; don't do the electric keys inside comments or strings,
   ;; and don't do bounce-indent with them.
-  (let ((parse-state (parse-partial-sexp (point-min) (point)))
+  (let ((parse-state (syntax-ppss (point)))
         (js2-bounce-indent-p (js2-code-at-bol-p)))
     (unless (or (nth 3 parse-state)
                 (nth 4 parse-state))
@@ -9779,11 +9779,12 @@ bound to KEY in the global keymap and indents the 
current line."
 
 (defun js-re-search-forward-inner (regexp &optional bound count)
   "Auxiliary function for `js-re-search-forward'."
-  (let ((parse)
-        (saved-point (point-min)))
+  (let (parse saved-point)
     (while (> count 0)
       (re-search-forward regexp bound)
-      (setq parse (parse-partial-sexp saved-point (point)))
+      (setq parse (if saved-point
+                      (parse-partial-sexp saved-point (point))
+                    (syntax-ppss (point))))
       (cond ((nth 3 parse)
              (re-search-forward
               (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
@@ -9819,11 +9820,12 @@ comments have been removed."
 
 (defun js-re-search-backward-inner (regexp &optional bound count)
   "Auxiliary function for `js-re-search-backward'."
-  (let ((parse)
-        (saved-point (point-min)))
+  (let (parse saved-point)
     (while (> count 0)
       (re-search-backward regexp bound)
-      (setq parse (parse-partial-sexp saved-point (point)))
+      (setq parse (if saved-point
+                      (parse-partial-sexp saved-point (point))
+                    (syntax-ppss (point))))
       (cond ((nth 3 parse)
              (re-search-backward
               (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
@@ -10336,8 +10338,7 @@ If so, we don't ever want to use bounce-indent."
         ;; This has to be set before calling parse-partial-sexp below.
         (inhibit-point-motion-hooks t))
     (setq parse-status (save-excursion
-                          (parse-partial-sexp (point-min)
-                                              (point-at-bol)))
+                          (syntax-ppss (point-at-bol)))
           offset (- (point) (save-excursion
                                (back-to-indentation)
                                (setq current-indent (current-column))
@@ -10723,7 +10724,7 @@ This ensures that the counts and `next-error' are 
correct."
   "Handle user pressing the Enter key."
   (interactive)
   (let ((parse-status (save-excursion
-                        (parse-partial-sexp (point-min) (point)))))
+                        (syntax-ppss (point)))))
     (cond
      ;; check if we're inside a string
      ((nth 3 parse-status)
@@ -10866,7 +10867,7 @@ Also moves past comment delimiters when inside 
comments."
   "Return non-nil if inside a string.
 Actually returns the quote character that begins the string."
    (let ((parse-state (save-excursion
-                        (parse-partial-sexp (point-min) (point)))))
+                        (syntax-ppss (point)))))
       (nth 3 parse-state)))
 
 (defsubst js2-mode-inside-comment-or-string ()
@@ -10880,7 +10881,7 @@ Actually returns the quote character that begins the 
string."
      (and comment-start
           (<= comment-start (point))))
    (let ((parse-state (save-excursion
-                        (parse-partial-sexp (point-min) (point)))))
+                        (syntax-ppss (point)))))
      (or (nth 3 parse-state)
          (nth 4 parse-state)))))
 
@@ -11030,7 +11031,7 @@ already have been inserted."
 (defun js2-mode-match-single-quote ()
   "Insert matching single-quote."
   (interactive)
-  (let ((parse-status (parse-partial-sexp (point-min) (point))))
+  (let ((parse-status (syntax-ppss (point))))
     ;; don't match inside comments, since apostrophe is more common
     (if (nth 4 parse-status)
         (insert "'")
@@ -11050,7 +11051,7 @@ already have been inserted."
   "Skip over close-paren rather than inserting, where appropriate."
   (interactive)
   (let* ((here (point))
-         (parse-status (parse-partial-sexp (point-min) here))
+         (parse-status (syntax-ppss here))
          (open-pos (nth 1 parse-status))
          (close last-input-event)
          (open (cond

commit db486b73c0af8becd41ccf83d7390e8e4a03d77a
Author: Dmitry Gutov <address@hidden>
Date:   Sun Apr 24 04:47:31 2011 +0400

    Skip unary ops before both semicolon checks

diff --git a/js2-mode.el b/js2-mode.el
index a11a60e..f4c1b1b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9917,15 +9917,15 @@ var a = 10,
     (save-excursion
       (back-to-indentation)
       (when (looking-at (concat js2-mode-identifier-re "[ \t]*=[^=]"))
-        (while (not (or at-opening-bracket
-                        ;; explicit semicolon
-                        (save-excursion (skip-chars-backward "-+~! ")
-                                        (js2-backward-sws)
-                                        (looking-back ";"))
-                        ;; implicit semicolon
-                        (save-excursion
-                          (and (progn (skip-chars-backward " \t")
-                                      (bolp))
+        (while (not (save-excursion
+                      ;; unary ops
+                      (skip-chars-backward "-+~! \t")
+                      (or at-opening-bracket
+                          ;; explicit semicolon
+                          (save-excursion (js2-backward-sws)
+                                          (looking-back ";"))
+                          ;; implicit semicolon
+                          (and (bolp)
                                (progn (js2-backward-sws)
                                       (not (looking-back ",")))
                                (progn (skip-chars-backward "[[:punct:]]")

commit 66eaec1c0e9a05ce9bb56ddfbd0501d66c669fe3
Author: Dmitry Gutov <address@hidden>
Date:   Sat Apr 23 22:20:54 2011 +0400

    Update README

diff --git a/README.md b/README.md
index c46d489..85e7e7b 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ In original js2-mode.el,
     bar = 20,
     baz = 30;
 
-In this js2-mode.el, when the value `js2-use-ast-for-indentation-p` is non-nil 
(default nil),
+In this js2-mode.el, when the value `js2-pretty-multiline-decl-indentation-p` 
is non-nil,
 
     var foo = 10,
         bar = 20,

commit 1c956a9150228986198d6f2a92381f8816a40df9
Author: Dmitry Gutov <address@hidden>
Date:   Sat Apr 23 21:17:32 2011 +0400

    Pretty-indent multiline declarations without AST

diff --git a/js2-mode.el b/js2-mode.el
index 4a5c98d..a11a60e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -234,8 +234,9 @@ regardless of the beginning bracket position."
   :group 'js2-mode
   :type 'boolean)
 
-(defcustom js2-use-ast-for-indentation-p nil
-  "Non-nil to use AST for indentation and make it more robust."
+(defcustom js2-pretty-multiline-decl-indentation-p t
+  "Non-nil to line up multiline declarations vertically. See the
+function `js-multiline-decl-indentation' for details."
   :group 'js2-mode
   :type 'boolean)
 
@@ -9750,6 +9751,10 @@ followed by an opening brace.")
   "Regular expression matching operators that affect indentation
 of continued expressions.")
 
+(defconst js-declaration-keyword-re
+  (regexp-opt '("var" "let" "const") 'words)
+  "Regular expression matching variable declaration keywords.")
+
 ;; This function has horrible results if you're typing an array
 ;; such as [[1, 2], [3, 4], [5, 6]].  Bounce indenting -really- sucks
 ;; in conjunction with electric-indent, so just disabling it.
@@ -9899,29 +9904,37 @@ indented to the same column as the current line."
                           "\\<while\\>" (point-at-eol) t))
                     (= (current-indentation) saved-indent)))))))))
 
-(defun js-get-multiline-declaration-offset ()
-  "Returns offset (> 0) if the current line is part of
- multi-line variable declaration like below example, and
- returns 0 otherwise.
-
- var a = 10,
-     b = 20,
-     c = 30;
+(defun js-multiline-decl-indentation ()
+  "Returns the proper indentation of the current line if it belongs
+to a multiline declaration statement.  All assignments are lined up vertically:
 
+var a = 10,
+    b = 20,
+    c = 30;
 "
-  (let* ((node (js2-node-at-point))
-         (pnode (and node (js2-node-parent node)))
-         (pnode-type (and pnode (js2-node-type pnode))))
-    (if (and node
-             (= js2-NAME (js2-node-type node))
-             (or
-              (= js2-VAR pnode-type)
-              (= js2-LET pnode-type)
-              (= js2-CONST pnode-type)))
-        (if (= js2-CONST pnode-type)
-            6
-          4)
-      0)))
+  (let (forward-sexp-function ; use lisp version
+        at-opening-bracket)
+    (save-excursion
+      (back-to-indentation)
+      (when (looking-at (concat js2-mode-identifier-re "[ \t]*=[^=]"))
+        (while (not (or at-opening-bracket
+                        ;; explicit semicolon
+                        (save-excursion (skip-chars-backward "-+~! ")
+                                        (js2-backward-sws)
+                                        (looking-back ";"))
+                        ;; implicit semicolon
+                        (save-excursion
+                          (and (progn (skip-chars-backward " \t")
+                                      (bolp))
+                               (progn (js2-backward-sws)
+                                      (not (looking-back ",")))
+                               (progn (skip-chars-backward "[[:punct:]]")
+                                      (not (looking-at 
js-indent-operator-re)))))))
+          (condition-case err
+              (backward-sexp)
+            (scan-error (setq at-opening-bracket t))))
+        (when (looking-at js-declaration-keyword-re)
+          (- (1+ (match-end 0)) (point-at-bol)))))))
 
 (defun js-ctrl-statement-indentation ()
   "Returns the proper indentation of the current line if it
@@ -9988,9 +10001,8 @@ In particular, return the buffer position of the first 
`for' kwd."
     (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
           (continued-expr-p (js-continued-expression-p))
-          (multiline-declaration-offset (or (and js2-use-ast-for-indentation-p
-                                                 
(js-get-multiline-declaration-offset))
-                                            0))
+          (declaration-indent (and js2-pretty-multiline-decl-indentation-p
+                                   (js-multiline-decl-indentation)))
           (bracket (nth 1 parse-status))
           beg)
       (cond
@@ -10005,6 +10017,8 @@ In particular, return the buffer position of the first 
`for' kwd."
 
        (ctrl-stmt-indent)
 
+       (declaration-indent)
+       
        (bracket
         (goto-char bracket)
         (cond
@@ -10022,8 +10036,6 @@ In particular, return the buffer position of the first 
`for' kwd."
                    (current-column))
                   (continued-expr-p
                    (+ (current-column) (* 2 js2-basic-offset)))
-                  ((> multiline-declaration-offset 0)
-                   (+ (current-column) js2-basic-offset 
multiline-declaration-offset))
                   (t
                    (+ (current-column) js2-basic-offset)))))
          (t
@@ -10034,9 +10046,6 @@ In particular, return the buffer position of the first 
`for' kwd."
 
        (continued-expr-p js2-basic-offset)
 
-       ((> multiline-declaration-offset 0)
-        (+ multiline-declaration-offset))
-
        (t 0)))))
 
 (defun js2-lineup-comment (parse-status)
@@ -10318,8 +10327,6 @@ If so, we don't ever want to use bounce-indent."
 (defun js2-indent-line (&optional bounce-backwards)
   "Indent the current line as JavaScript source text."
   (interactive)
-  (when js2-use-ast-for-indentation-p
-    (js2-reparse))
   (let (parse-status
         current-indent
         offset

commit b300b57228d9b5098b34b14a657e8b0fb8abceb4
Author: Dmitry Gutov <address@hidden>
Date:   Thu Apr 21 21:59:22 2011 +0400

    Simplify `js-ctrl-statement-indentation'

diff --git a/js2-mode.el b/js2-mode.el
index 8899169..4a5c98d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9737,18 +9737,13 @@ not `js2-NAME', then we use the token info saved in 
instance vars."
 ;; Karl for coming up with the initial approach, which packs a lot of
 ;; punch for so little code.
 
-(defconst js-possibly-braceless-keyword-re
-  (regexp-opt
-   '("catch" "do" "else" "finally" "for" "if" "each" "try" "while" "with" 
"let")
-   'words)
+(defconst js-possibly-braceless-keywords-re
+  (concat "else[ \t]+if\\|for[ \t]+each\\|"
+          (regexp-opt '("catch" "do" "else" "finally" "for" "if"
+                        "try" "while" "with" "let")))
   "Regular expression matching keywords that are optionally
 followed by an opening brace.")
 
-(defconst js-possibly-braceless-keywords-re
-  "\\([ \t}]*else[ \t]+if\\|[ \t}]*for[ \t]+each\\)"
-  "Regular expression which matches the keywords which are consist of more 
than 2 words
-like 'if else' and 'for each', and optionally followed by an opening brace.")
-
 (defconst js-indent-operator-re
   (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
           (regexp-opt '("in" "instanceof") 'words))
@@ -9935,28 +9930,22 @@ returns nil."
   (let (forward-sexp-function)  ; temporarily unbind it
     (save-excursion
       (back-to-indentation)
-      (when (save-excursion
-              (and (not (js2-same-line (point-min)))
-                   (not (looking-at "{"))
-                   (js-re-search-backward "[[:graph:]]" nil t)
-                   (not (looking-at "[{([]"))
-                   (progn
-                     (forward-char)
+      (when (and (not (js2-same-line (point-min)))
+                 (not (looking-at "{"))
+                 (js-re-search-backward "[[:graph:]]" nil t)
+                 (not (looking-at "[{([]"))
+                 (progn
+                   (forward-char)
+                   (when (looking-back ")")
                      ;; scan-sexps sometimes throws an error
                      (ignore-errors (backward-sexp))
-                     (when (looking-at "(") (backward-word 1))
-                     (and (save-excursion
-                            (skip-chars-backward " \t}" (point-at-bol))
-                            (or (bolp)
-                                (and (backward-word 1)
-                                     (skip-chars-backward " \t}" 
(point-at-bol))
-                                     (bolp)
-                                     (looking-at 
js-possibly-braceless-keywords-re))))
-                          (looking-at js-possibly-braceless-keyword-re)
+                     (skip-chars-backward " \t" (point-at-bol)))
+                   (let ((pt (point)))
+                     (back-to-indentation)
+                     (and (looking-at js-possibly-braceless-keywords-re)
+                          (= (match-end 0) pt)
                           (not (js-end-of-do-while-loop-p))))))
-        (save-excursion
-          (goto-char (match-beginning 0))
-          (+ (current-indentation) js2-basic-offset))))))
+        (+ (current-indentation) js2-basic-offset)))))
 
 (defun js2-indent-in-array-comp (parse-status)
   "Return non-nil if we think we're in an array comprehension.

commit 90c6f5fba1e1841cc93941cc2dbf6648675f7204
Author: Dmitry Gutov <address@hidden>
Date:   Thu Apr 21 02:53:14 2011 +0400

    Don't discard the value of `js2-additional-externs'
    
    The doc says it can be set in `js2-mode-hook', but `js2-reparse' discarded
    the resulting value.
    
    http://code.google.com/p/js2-mode/issues/detail?id=117

diff --git a/js2-mode.el b/js2-mode.el
index 5e1dcb4..8899169 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7368,9 +7368,10 @@ Scanner should be initialized."
         (js2-node-add-children root comment)))
     (setf (js2-node-len root) (- end pos))
     ;; Give extensions a chance to muck with things before highlighting starts.
-    (dolist (callback js2-post-parse-callbacks)
-      (funcall callback))
-    (js2-highlight-undeclared-vars)
+    (let ((js2-additional-externs js2-additional-externs))
+      (dolist (callback js2-post-parse-callbacks)
+        (funcall callback))
+      (js2-highlight-undeclared-vars))
     root))
 
 (defun js2-function-parser ()
@@ -10552,8 +10553,7 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
             (js2-with-unmodifying-text-property-changes
               (setq js2-mode-buffer-dirty-p nil
                     js2-mode-fontifications nil
-                    js2-mode-deferred-properties nil
-                    js2-additional-externs nil)
+                    js2-mode-deferred-properties nil)
               (if js2-mode-verbose-parse-p
                   (message "parsing..."))
               (setq time

commit 88e1c8c75f8b6cd1249934cd5ad91565798fb2e8
Author: mooz <address@hidden>
Date:   Tue Apr 12 11:06:43 2011 +0800

    Fix for regexp literals with slashes in brackets.
    
    Correctly highlight literals like /foo[/]bar/.

diff --git a/coffee-mode.el b/coffee-mode.el
index 6a6c005..6ae08a5 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -250,7 +250,7 @@ path."
 (defvar coffee-boolean-regexp 
"\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\)\\b")
 
 ;; Regular Expressions
-(defvar coffee-regexp-regexp "\\/\\([^\\]\\|\\\\.\\)+?\\/")
+(defvar coffee-regexp-regexp 
"\\/\\(\\\\.\\|\\[\\(\\\\.\\|.\\)+?\\]\\|[^/]\\)+?\\/")
 
 ;; JavaScript Keywords
 (defvar coffee-js-keywords

commit 1f9bc1a93e85eb70c46136888d7e30ac1204f71f
Author: mark hellewell <address@hidden>
Date:   Tue Apr 5 07:47:53 2011 +0800

    nodejs.org docs changed location.

diff --git a/coffee-mode.el b/coffee-mode.el
index 2334043..6a6c005 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -197,9 +197,9 @@ path."
   (browse-url "http://jashkenas.github.com/coffee-script/";))
 
 (defun coffee-open-node-reference ()
-  "Open browser to node.js reference."
+  "Open browser to node.js documentation."
   (interactive)
-  (browse-url "http://nodejs.org/api.html";))
+  (browse-url "http://nodejs.org/docs/";))
 
 (defun coffee-open-github ()
   "Open browser to `coffee-mode' project on GithHub."

commit fce2bb756a266873cf3b35feaa74c9a8e73bef58
Author: mooz <address@hidden>
Date:   Thu Apr 7 11:53:29 2011 +0900

    fix documentation

diff --git a/README.md b/README.md
index d17a283..c46d489 100644
--- a/README.md
+++ b/README.md
@@ -22,10 +22,10 @@ See 
<http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for detail
 Differences between original js2-mode.el
 ========================================
 
-Supported more popular indentation style
-----------------------------------------
+Popular indentation style
+-------------------------
 
-When js2-consistent-level-indent-inner-bracket-p is non-nil
+When `js2-consistent-level-indent-inner-bracket-p` is non-nil
     
     [foo, bar, baz].forEach(function (v) {
         if (validate(v))
@@ -36,7 +36,7 @@ When js2-consistent-level-indent-inner-bracket-p is non-nil
         return validate(v);
     });
 
-When js2-consistent-level-indent-inner-bracket-p is nil
+When `js2-consistent-level-indent-inner-bracket-p` is nil
 (Same as original js2-mode's indentation)
 
     [foo, bar, baz].forEach(function (v) {
@@ -63,8 +63,8 @@ In this js2-mode.el, when the value 
`js2-use-ast-for-indentation-p` is non-nil (
         bar = 20,
         baz = 30;
 
-Support for abbreviated destructuring assignments
--------------------------------------------------
+Abbreviated destructuring assignments
+-------------------------------------
 
     let {a, b}       = {a: 10, b: 20}; // Abbreviated   (Not supported in 
original js2-mode.el)
     let {a: a, b: b} = {a: 10, b: 20}; // Same as above (Supported in original 
js2-mode.el)
@@ -74,8 +74,8 @@ Support for abbreviated destructuring assignments
     for (let [k, { name, age }] in Iterator(obj)) // nested
         print(k, name, age);
 
-Support for expression closure in property value
-------------------------------------------------
+Expression closure in property value
+------------------------------------
 
     let worker = {
         get age() 20,
@@ -83,8 +83,8 @@ Support for expression closure in property value
         fire: function () _fire()
     };
 
-Fixed odd indentation of "else if" with no braces
------------------------------------------------------
+Fix for odd indentation of "else if" with no braces
+---------------------------------------------------
 
 In original js2-mode.el,
 

commit 3e8092ec1be7df0a990be78bee4a93581b0cc5ae
Author: mooz <address@hidden>
Date:   Wed Apr 6 23:47:38 2011 +0900

    allow bare CDATA section e.g. let xml = <![CDATA[ foo bar baz ]]>;

diff --git a/js2-mode.el b/js2-mode.el
index 50a7645..5e1dcb4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6103,7 +6103,11 @@ corresponding number.  Otherwise return -1."
                            (throw 'return js2-ERROR)))
                         (t
                          (unless (js2-read-entity)
-                           (throw 'return js2-ERROR)))))
+                           (throw 'return js2-ERROR))))
+                      ;; allow bare CDATA section
+                      ;; ex) let xml = <![CDATA[ foo bar baz ]]>;
+                      (when (zerop js2-ts-xml-open-tags-count)
+                        (throw 'return js2-XMLEND)))
                      (??
                       (setq c (js2-get-char)) ;; skip ?
                       (js2-add-to-string c)

commit 174c51d030e15406f7fbac49df4fede7a199597c
Author: Dmitry Gutov <address@hidden>
Date:   Mon Apr 4 22:09:12 2011 +0400

    Improve documentation
    
    Using `batch-byte-compile' function to make the command work under MS 
Windows.

diff --git a/README.md b/README.md
index 3f863f1..d17a283 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Install
 
     $ git clone git://github.com/mooz/js2-mode.git
     $ cd js2-mode
-    $ emacs --batch --eval '(byte-compile-file "js2-mode.el")'
+    $ emacs --batch -f batch-byte-compile js2-mode.el
 
 Then, place js2-mode.elc into your site-lisp directory.
 
diff --git a/js2-mode.el b/js2-mode.el
index 8f30caf..50a7645 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -223,7 +223,8 @@ based on heuristic guessing.  If non-nil, then if the 
current line is
 already indented to that predetermined column, indenting will choose
 another likely column and indent to that spot.  Repeated invocation of
 the indent-line function will cycle among the computed alternatives.
-See the function `js2-bounce-indent' for details."
+See the function `js2-bounce-indent' for details.  When it is non-nil,
+js2-mode also binds `js2-bounce-indent-backwards' to Shift-Tab."
   :type 'boolean
   :group 'js2-mode)
 
@@ -6870,8 +6871,8 @@ that it's an external variable, which must also be in the 
top-level scope."
       (js2-ast-root-p defining-scope))
      (t t))))
 
-(defsubst js2-anonymous-wrapper-fn-p (node)
-  "Returns t if NODE is an anonymous function that's invoked immediately.
+(defsubst js2-wrapper-function-p (node)
+  "Returns t if NODE is a function expression that's immediately invoked.
 NODE must be `js2-function-node'."
   (let ((parent (js2-node-parent node)))
     (or
@@ -6916,7 +6917,7 @@ For instance, following a 'this' reference requires a 
parent function node."
                         ((setq parent-chain
                                (gethash fn js2-imenu-function-map))
                          'named)
-                        ((js2-anonymous-wrapper-fn-p fn) 'anon)
+                        ((js2-wrapper-function-p fn) 'anon)
                         (t 'skip)))
             (puthash fn fn-type js2-imenu-fn-type-map))
           (case fn-type

commit 5b1bfa269153faf48446e2f57fc5e55fb628a4c5
Author: mooz <address@hidden>
Date:   Sat Apr 2 12:49:37 2011 +0900

    imenu: accept paren-free direct function call in 
`js2-anonymous-wrapper-fn-p'
    
    // not supported before this commit
    var a = function () {
        function bar() {
        }
    }();
    
    // supported
    var b = (function () {
        function foo() {
        }
    })();

diff --git a/js2-mode.el b/js2-mode.el
index af28a3f..8f30caf 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6874,14 +6874,17 @@ that it's an external variable, which must also be in 
the top-level scope."
   "Returns t if NODE is an anonymous function that's invoked immediately.
 NODE must be `js2-function-node'."
   (let ((parent (js2-node-parent node)))
-    (and (js2-paren-node-p parent)
-         ;; (function(){...})();
-         (or (js2-call-node-p (setq parent (js2-node-parent parent)))
-             ;; (function(){...}).call(this);
-             (and (js2-prop-get-node-p parent)
-                  (member (js2-name-node-name (js2-prop-get-node-right parent))
-                          '("call" "apply"))
-                  (js2-call-node-p (js2-node-parent parent)))))))
+    (or
+     ;; function(){...}();
+     (js2-call-node-p parent)
+     (and (js2-paren-node-p parent)
+          ;; (function(){...})();
+          (or (js2-call-node-p (setq parent (js2-node-parent parent)))
+              ;; (function(){...}).call(this);
+              (and (js2-prop-get-node-p parent)
+                   (member (js2-name-node-name (js2-prop-get-node-right 
parent))
+                           '("call" "apply"))
+                   (js2-call-node-p (js2-node-parent parent))))))))
 
 (defun js2-browse-postprocess-chains (chains)
   "Modify function-declaration name chains after parsing finishes.

commit 6753f5ac403d5f1e5f042e5a2be63052e613b3ae
Author: mooz <address@hidden>
Date:   Tue Mar 29 00:03:51 2011 +0900

    Refined code (Thanks dgutov)
    
    
https://github.com/mooz/js2-mode/commit/09a9e5e94c7175535e525d9f0645b1e4fc7bd404#commitcomment-318882

diff --git a/js2-mode.el b/js2-mode.el
index 2a667d7..af28a3f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7924,7 +7924,10 @@ Parses for, for-in, and for each-in statements."
       (if (js2-match-token js2-IN)
           (setq is-for-in t
                 in-pos (- js2-token-beg for-pos)
-                cond (js2-parse-expr))  ; object over which we're iterating
+                ;; scope of iteration target object is not the scope we've 
created above.
+                ;; stash current scope temporary.
+                cond (let ((js2-current-scope (js2-scope-parent-scope 
js2-current-scope)))
+                       (js2-parse-expr)))  ; object over which we're iterating
         ;; else ordinary for loop - parse cond and incr
         (js2-must-match js2-SEMI "msg.no.semi.for")
         (setq cond (if (= (js2-peek-token) js2-SEMI)

commit 6a084ba247eb59e2f5e0cdbcc379a0064d29f9f3
Author: mooz <address@hidden>
Date:   Tue Mar 29 00:00:25 2011 +0900

    Revert "don't use inner scope of `for` for iteration target."
    
    This reverts commit 09a9e5e94c7175535e525d9f0645b1e4fc7bd404.

diff --git a/js2-mode.el b/js2-mode.el
index 6e558f4..2a667d7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7229,10 +7229,10 @@ Returns t on match, nil if no match."
   (unless js2-compiler-xml-available
     (js2-report-error "msg.XML.not.available")))
 
-(defsubst js2-push-scope (scope &optional overwrite-parent)
+(defsubst js2-push-scope (scope)
   "Push SCOPE, a `js2-scope', onto the lexical scope chain."
   (assert (js2-scope-p scope))
-  (or overwrite-parent (assert (null (js2-scope-parent-scope scope))))
+  (assert (null (js2-scope-parent-scope scope)))
   (assert (not (eq js2-current-scope scope)))
   (setf (js2-scope-parent-scope scope) js2-current-scope
         js2-current-scope scope))
@@ -7924,13 +7924,7 @@ Parses for, for-in, and for each-in statements."
       (if (js2-match-token js2-IN)
           (setq is-for-in t
                 in-pos (- js2-token-beg for-pos)
-                cond (let ((for-body-scope js2-current-scope))
-                       ;; scope of iteration target object is not the scope 
we've created above.
-                       ;; stash current scope temporary.
-                       (js2-pop-scope)
-                       (unwind-protect
-                           (js2-parse-expr) ; object over which we're iterating
-                         (js2-push-scope for-body-scope t))))
+                cond (js2-parse-expr))  ; object over which we're iterating
         ;; else ordinary for loop - parse cond and incr
         (js2-must-match js2-SEMI "msg.no.semi.for")
         (setq cond (if (= (js2-peek-token) js2-SEMI)

commit 09a9e5e94c7175535e525d9f0645b1e4fc7bd404
Author: mooz <address@hidden>
Date:   Mon Mar 28 21:31:56 2011 +0900

    don't use inner scope of `for` for iteration target.

diff --git a/js2-mode.el b/js2-mode.el
index 2a667d7..6e558f4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7229,10 +7229,10 @@ Returns t on match, nil if no match."
   (unless js2-compiler-xml-available
     (js2-report-error "msg.XML.not.available")))
 
-(defsubst js2-push-scope (scope)
+(defsubst js2-push-scope (scope &optional overwrite-parent)
   "Push SCOPE, a `js2-scope', onto the lexical scope chain."
   (assert (js2-scope-p scope))
-  (assert (null (js2-scope-parent-scope scope)))
+  (or overwrite-parent (assert (null (js2-scope-parent-scope scope))))
   (assert (not (eq js2-current-scope scope)))
   (setf (js2-scope-parent-scope scope) js2-current-scope
         js2-current-scope scope))
@@ -7924,7 +7924,13 @@ Parses for, for-in, and for each-in statements."
       (if (js2-match-token js2-IN)
           (setq is-for-in t
                 in-pos (- js2-token-beg for-pos)
-                cond (js2-parse-expr))  ; object over which we're iterating
+                cond (let ((for-body-scope js2-current-scope))
+                       ;; scope of iteration target object is not the scope 
we've created above.
+                       ;; stash current scope temporary.
+                       (js2-pop-scope)
+                       (unwind-protect
+                           (js2-parse-expr) ; object over which we're iterating
+                         (js2-push-scope for-body-scope t))))
         ;; else ordinary for loop - parse cond and incr
         (js2-must-match js2-SEMI "msg.no.semi.for")
         (setq cond (if (= (js2-peek-token) js2-SEMI)

commit c783bd4bbcd97e1edfdd3765396e433c1b7a3804
Author: mooz <address@hidden>
Date:   Mon Mar 28 19:03:46 2011 +0900

    give correct scope for `for` statement

diff --git a/js2-mode.el b/js2-mode.el
index 6aa2f2f..2a667d7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7908,66 +7908,70 @@ Parses for, for-in, and for each-in statements."
     (if (js2-must-match js2-LP "msg.no.paren.for")
         (setq lp (- js2-token-beg for-pos)))
     (setq tt (js2-peek-token))
-    ;; parse init clause
-    (let ((js2-in-for-init t))  ; set as dynamic variable
-      (cond
-       ((= tt js2-SEMI)
-        (setq init (make-js2-empty-expr-node)))
-       ((or (= tt js2-VAR) (= tt js2-LET))
-        (js2-consume-token)
-        (setq init (js2-parse-variables tt js2-token-beg)))
-       (t
-        (setq init (js2-parse-expr)))))
-    (if (js2-match-token js2-IN)
-        (setq is-for-in t
-              in-pos (- js2-token-beg for-pos)
-              cond (js2-parse-expr))  ; object over which we're iterating
-      ;; else ordinary for loop - parse cond and incr
-      (js2-must-match js2-SEMI "msg.no.semi.for")
-      (setq cond (if (= (js2-peek-token) js2-SEMI)
-                     (make-js2-empty-expr-node) ; no loop condition
-                   (js2-parse-expr)))
-      (js2-must-match js2-SEMI "msg.no.semi.for.cond")
-      (setq tmp-pos js2-token-end
-            incr (if (= (js2-peek-token) js2-RP)
-                     (make-js2-empty-expr-node :pos tmp-pos)
-                   (js2-parse-expr))))
-    (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
-        (setq rp (- js2-token-beg for-pos)))
-    (if (not is-for-in)
-        (setq pn (make-js2-for-node :init init
-                                    :condition cond
-                                    :update incr
-                                    :lp lp
-                                    :rp rp))
-      ;; cond could be null if 'in obj' got eaten by the init node.
-      (if (js2-infix-node-p init)
-          ;; it was (foo in bar) instead of (var foo in bar)
-          (setq cond (js2-infix-node-right init)
-                init (js2-infix-node-left init))
-        (if (and (js2-var-decl-node-p init)
-                 (> (length (js2-var-decl-node-kids init)) 1))
-            (js2-report-error "msg.mult.index")))
-      (setq pn (make-js2-for-in-node :iterator init
-                                     :object cond
-                                     :in-pos in-pos
-                                     :foreach-p is-for-each
-                                     :each-pos each-pos
-                                     :lp lp
-                                     :rp rp)))
+    ;; 'for' makes local scope
+    (js2-push-scope (make-js2-scope))
     (unwind-protect
-        (progn
-          (js2-enter-loop pn)
-          ;; We have to parse the body -after- creating the loop node,
-          ;; so that the loop node appears in the js2-loop-set, allowing
-          ;; break/continue statements to find the enclosing loop.
-          (setf body (js2-parse-statement)
-                (js2-loop-node-body pn) body
-                (js2-node-pos pn) for-pos
-                (js2-node-len pn) (- (js2-node-end body) for-pos))
-          (js2-node-add-children pn init cond incr body))
-      ;; finally
-      (js2-exit-loop))
+        ;; parse init clause
+        (let ((js2-in-for-init t))  ; set as dynamic variable
+          (cond
+           ((= tt js2-SEMI)
+            (setq init (make-js2-empty-expr-node)))
+           ((or (= tt js2-VAR) (= tt js2-LET))
+            (js2-consume-token)
+            (setq init (js2-parse-variables tt js2-token-beg)))
+           (t
+            (setq init (js2-parse-expr)))))
+      (if (js2-match-token js2-IN)
+          (setq is-for-in t
+                in-pos (- js2-token-beg for-pos)
+                cond (js2-parse-expr))  ; object over which we're iterating
+        ;; else ordinary for loop - parse cond and incr
+        (js2-must-match js2-SEMI "msg.no.semi.for")
+        (setq cond (if (= (js2-peek-token) js2-SEMI)
+                       (make-js2-empty-expr-node) ; no loop condition
+                     (js2-parse-expr)))
+        (js2-must-match js2-SEMI "msg.no.semi.for.cond")
+        (setq tmp-pos js2-token-end
+              incr (if (= (js2-peek-token) js2-RP)
+                       (make-js2-empty-expr-node :pos tmp-pos)
+                     (js2-parse-expr))))
+      (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
+          (setq rp (- js2-token-beg for-pos)))
+      (if (not is-for-in)
+          (setq pn (make-js2-for-node :init init
+                                      :condition cond
+                                      :update incr
+                                      :lp lp
+                                      :rp rp))
+        ;; cond could be null if 'in obj' got eaten by the init node.
+        (if (js2-infix-node-p init)
+            ;; it was (foo in bar) instead of (var foo in bar)
+            (setq cond (js2-infix-node-right init)
+                  init (js2-infix-node-left init))
+          (if (and (js2-var-decl-node-p init)
+                   (> (length (js2-var-decl-node-kids init)) 1))
+              (js2-report-error "msg.mult.index")))
+        (setq pn (make-js2-for-in-node :iterator init
+                                       :object cond
+                                       :in-pos in-pos
+                                       :foreach-p is-for-each
+                                       :each-pos each-pos
+                                       :lp lp
+                                       :rp rp)))
+      (unwind-protect
+          (progn
+            (js2-enter-loop pn)
+            ;; We have to parse the body -after- creating the loop node,
+            ;; so that the loop node appears in the js2-loop-set, allowing
+            ;; break/continue statements to find the enclosing loop.
+            (setf body (js2-parse-statement)
+                  (js2-loop-node-body pn) body
+                  (js2-node-pos pn) for-pos
+                  (js2-node-len pn) (- (js2-node-end body) for-pos))
+            (js2-node-add-children pn init cond incr body))
+        ;; finally
+        (js2-exit-loop))
+      (js2-pop-scope))
     pn))
 
 (defun js2-parse-try ()

commit c06137d59c5908fa0f7ca148c70e73c89833907f
Merge: 6e2677e 8658974
Author: mooz <address@hidden>
Date:   Mon Mar 28 18:07:17 2011 +0900

    Merge branch 'bounce-indent' of https://github.com/dgutov/js2-mode into 
dgutov-bounce-indent


commit 86589743a25e8bf084e6e6893517a3ecee993450
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 24 18:28:28 2011 +0300

    bounce-indent: properly find the fourth likely point
    
    Properly find the fourth likely point even when the cursor is
    not inside indentation.

diff --git a/js2-mode.el b/js2-mode.el
index ef1bcc2..8dc31e1 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10216,6 +10216,7 @@ in reverse."
           ;; fourth likely point:  first preceding code with less indentation
           ;; than the immediately preceding code line.
           (setq pos (save-excursion
+                      (back-to-indentation)
                       (js2-backward-sws)
                       (back-to-indentation)
                       (setq anchor (current-column))
@@ -10229,7 +10230,7 @@ in reverse."
 
           ;; nesting-heuristic position, main by default
           (push (setq main-pos normal-col) positions)
-
+          
           ;; delete duplicates and sort positions list
           (setq positions (sort (delete-dups positions) '<))
           
@@ -10248,7 +10249,7 @@ in reverse."
           
           ;; record whether we're already sitting on one of the alternatives
           (setq pos (member cur-indent positions))
-
+          
           (cond
            ;; case 0:  we're one one of the alternatives and this is the
            ;; first time they've pressed TAB on this line (best-guess).
@@ -10280,7 +10281,7 @@ in reverse."
                 finally do
                 (unless (or result (null computed-pos))
                   (indent-line-to (nth computed-pos positions)))))
-
+      
       ;; finally
       (if js2-mode-indent-inhibit-undo
           (setq buffer-undo-list old-buffer-undo-list))

commit b5623fd111963fbdf5246b9327c03ec6f364c246
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 26 10:16:47 2011 +0100

    (ioccur-jump-without-quit): Allow saving mark to mark-ring.bound to C-SPC.

diff --git a/ioccur.el b/ioccur.el
index 34c641a..ec68616 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -550,7 +550,7 @@ Move point to first occurence of `ioccur-pattern'."
       (if win-conf
           (set-window-configuration win-conf)
           (pop-to-buffer ioccur-current-buffer))
-      (ioccur-goto-line pos) (recenter)
+      (ioccur-goto-line pos) (recenter) (set-marker (mark-marker) (point))
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-pattern'.
       (when (funcall ioccur-search-function
@@ -568,11 +568,12 @@ Move point to first occurence of `ioccur-pattern'."
       (delete-overlay ioccur-match-overlay))))
 
 ;;;###autoload
-(defun ioccur-jump-without-quit ()
-  "Jump to line in `ioccur-current-buffer' without quiting."
+(defun ioccur-jump-without-quit (&optional mark)
+  "Jump to line in `ioccur-current-buffer' without quitting."
   (interactive)
-  (and (ioccur-jump ioccur-last-window-configuration)
-       (switch-to-buffer-other-window ioccur-buffer t)))
+  (when (ioccur-jump ioccur-last-window-configuration)
+    (when mark (push-mark (point) 'nomsg))
+    (switch-to-buffer-other-window ioccur-buffer t)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()
@@ -745,6 +746,8 @@ START-POINT is the point where we start searching in 
buffer."
                   (setq ioccur-quit-flag t) nil)
                  ((right ?\C-z)                 ; Persistent action.
                   (ioccur-jump-without-quit) t)
+                 ((?\C- )                       ; Persistent action save mark.
+                  (ioccur-jump-without-quit t) t)                 
                  ((left ?\C-j)                  ; Jump and kill search buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
                  ((next ?\C-v)                  ; Scroll down.
@@ -820,6 +823,7 @@ C-n or <down>      Next line.\n
 C-p or <up>        Precedent line.\n
 C-v and M-v/C-t    Scroll up and down.\n
 C-z or <right>     Jump without quitting loop.\n
+C-TAB              Jump without quitting and save to mark-ring.\n
 C-j or <left>      Jump and kill `ioccur-buffer'.\n
 RET                Exit keeping `ioccur-buffer'.\n
 DEL                Remove last character entered.\n

commit d6e9f343c9615aae2049acc162451fe0c8a3f89e
Author: Dmitry Gutov <address@hidden>
Date:   Thu Mar 24 18:26:55 2011 +0300

    Sort all bounce positions by indent size

diff --git a/js2-mode.el b/js2-mode.el
index 580cffb..ef1bcc2 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10137,6 +10137,7 @@ in reverse."
                         (1+ (count-lines (point-min) (point)))))
         positions
         pos
+        main-pos
         anchor
         arglist-cont
         same-indent
@@ -10186,8 +10187,7 @@ in reverse."
                           (current-column)))))
           (when pos
             (incf pos js2-basic-offset)
-            (unless (member pos positions)
-              (push pos positions)))
+            (push pos positions))
 
           ;; third likely point:  same indent as previous line of code.
           ;; Make it the first likely point if we're not on an
@@ -10211,8 +10211,7 @@ in reverse."
                          (js2-indent-in-objlit-p parse-status))
                      (not (js2-arglist-close)))
                 (setq same-indent pos))
-            (unless (member pos positions)
-              (push pos positions)))
+            (push pos positions))
 
           ;; fourth likely point:  first preceding code with less indentation
           ;; than the immediately preceding code line.
@@ -10226,25 +10225,22 @@ in reverse."
                                         (current-column))
                                       anchor)))
                       (setq pos (current-column))))
-          (unless (member pos positions)
-            (push pos positions))
+          (push pos positions)
 
-          ;; put nesting-heuristic position first in list, sort rest
-          (setq positions (nreverse (sort positions '<)))
-          (setq positions (cons normal-col (delete normal-col positions)))
+          ;; nesting-heuristic position, main by default
+          (push (setq main-pos normal-col) positions)
 
+          ;; delete duplicates and sort positions list
+          (setq positions (sort (delete-dups positions) '<))
+          
           ;; comma-list continuation lines:  prev line indent takes precedence
           (if same-indent
-              (setq positions
-                    (cons same-indent
-                          (sort (delete same-indent positions) '<))))
+              (setq main-pos same-indent))
 
           ;; common special cases where we want to indent in from previous line
           (if (or (js2-indent-case-block-p)
                   (js2-indent-objlit-arg-p parse-status))
-              (setq positions
-                    (cons basic-offset
-                          (delete basic-offset positions))))
+              (setq main-pos basic-offset))
 
           ;; if bouncing backwards, reverse positions list
           (if backwards
@@ -10267,14 +10263,14 @@ in reverse."
             (setq computed-pos 0))
            ;; case 2:  not on any of the computed spots => use main spot
            ((not pos)
-            (setq computed-pos 0))
+            (setq computed-pos (js2-position main-pos positions)))
            ;; case 3:  on last position:  cycle to first position
            ((null (cdr pos))
             (setq computed-pos 0))
            ;; case 4:  on intermediate position:  cycle to next position
            (t
             (setq computed-pos (js2-position (second pos) positions))))
-
+          
           ;; see if any hooks want to indent; otherwise we do it
           (loop with result = nil
                 for hook in js2-indent-hook

commit 9e8d316f98ee52d9a982dcda22d46a5d4e24bede
Author: Dmitry Gutov <address@hidden>
Date:   Wed Mar 23 15:15:15 2011 +0300

    Add js2-indent-bounce-backwards

diff --git a/js2-mode.el b/js2-mode.el
index 9d12060..580cffb 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1181,6 +1181,8 @@ another file, or you've got a potential bug."
       (mapc (lambda (key)
               (define-key map key #'js2-insert-and-indent))
             js2-electric-keys))
+    (when js2-bounce-indent-p
+      (define-key map (kbd "<backtab>") #'js2-indent-bounce-backwards))
 
     (define-key map [menu-bar javascript]
       (cons "JavaScript" (make-sparse-keymap "JavaScript")))
@@ -10120,12 +10122,13 @@ Returns `point-at-bol' if the line is empty."
     (skip-chars-forward " \t")
     (point)))
 
-(defun js2-bounce-indent (normal-col parse-status)
+(defun js2-bounce-indent (normal-col parse-status backwards)
   "Cycle among alternate computed indentation positions.
 PARSE-STATUS is the result of `parse-partial-sexp' from the beginning
 of the buffer to the current point.  NORMAL-COL is the indentation
 column computed by the heuristic guesser based on current paren,
-bracket, brace and statement nesting."
+bracket, brace and statement nesting.  If BACKWARDS, cycle positions
+in reverse."
   (let ((cur-indent (js2-current-indent))
         (old-buffer-undo-list buffer-undo-list)
         ;; Emacs 21 only has `count-lines', not `line-number-at-pos'
@@ -10243,8 +10246,13 @@ bracket, brace and statement nesting."
                     (cons basic-offset
                           (delete basic-offset positions))))
 
+          ;; if bouncing backwards, reverse positions list
+          (if backwards
+              (setq positions (reverse positions)))
+          
           ;; record whether we're already sitting on one of the alternatives
           (setq pos (member cur-indent positions))
+
           (cond
            ;; case 0:  we're one one of the alternatives and this is the
            ;; first time they've pressed TAB on this line (best-guess).
@@ -10283,6 +10291,12 @@ bracket, brace and statement nesting."
       ;; see commentary for `js2-mode-last-indented-line'
       (setq js2-mode-last-indented-line current-line))))
 
+(defun js2-indent-bounce-backwards ()
+  "Calls `js2-indent-line'.  When `js2-bounce-indent-p',
+cycles between the computed indentation positions in reverse order."
+  (interactive)
+  (js2-indent-line t))
+
 (defsubst js2-1-line-comment-continuation-p ()
   "Return t if we're in a 1-line comment continuation.
 If so, we don't ever want to use bounce-indent."
@@ -10299,7 +10313,7 @@ If so, we don't ever want to use bounce-indent."
                (forward-line 0))
              (looking-at "\\s-*//"))))))
 
-(defun js2-indent-line ()
+(defun js2-indent-line (&optional bounce-backwards)
   "Indent the current line as JavaScript source text."
   (interactive)
   (when js2-use-ast-for-indentation-p
@@ -10331,7 +10345,7 @@ If so, we don't ever want to use bounce-indent."
             ((and js2-bounce-indent-p
                   (not (js2-same-line (point-min)))
                   (not (js2-1-line-comment-continuation-p)))
-             (js2-bounce-indent indent-col parse-status)
+             (js2-bounce-indent indent-col parse-status bounce-backwards)
              (setq moved t))
             ;; just indent to the guesser's likely spot
             ((/= current-indent indent-col)

commit 12f33f359cd4469dddfa454fe47715190dc025e3
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 22 18:56:36 2011 +0300

    Make comment-* vars buffer-local
    
    http://code.google.com/p/js2-mode/issues/detail?id=86

diff --git a/js2-mode.el b/js2-mode.el
index be8cf5f..9d12060 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10355,6 +10355,9 @@ If so, we don't ever want to use bounce-indent."
   (kill-all-local-variables)
   (set-syntax-table js2-mode-syntax-table)
   (use-local-map js2-mode-map)
+  (make-local-variable 'comment-start)
+  (make-local-variable 'comment-end)
+  (make-local-variable 'comment-start-skip)
   (setq major-mode 'js2-mode
         mode-name "JavaScript-IDE"
         comment-start "//"  ; used by comment-region; don't change it

commit 8a0076a7640db8ca488a8f300c1c46cda397761e
Author: Dmitry Gutov <address@hidden>
Date:   Tue Mar 22 16:21:54 2011 +0300

    Declare non-let symbols in current function or script, not block scope
    
    if (true) {
      function boo() {}
    }
    
    boo(); // declared
    
    for (var i = 0; i < 4; ++i) { var j = i + 2; }
    
    alert(i + ", " + j) // 4, 5

diff --git a/js2-mode.el b/js2-mode.el
index 9defd18..be8cf5f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -8531,8 +8531,8 @@ by `js2-parse-variables'."
       (js2-pop-scope))
     pn))
 
-(defsubst js2-define-new-symbol (decl-type name node)
-  (js2-scope-put-symbol js2-current-scope
+(defsubst js2-define-new-symbol (decl-type name node &optional scope)
+  (js2-scope-put-symbol (or scope js2-current-scope)
                         name
                         (make-js2-symbol decl-type name node)))
 
@@ -8572,7 +8572,8 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
               (js2-add-strict-warning "msg.var.redecl" name)
             (if (and js2-strict-var-hides-function-arg-warning (= sdt js2-LP))
                 (js2-add-strict-warning "msg.var.hides.arg" name)))
-        (js2-define-new-symbol decl-type name node)))
+        (js2-define-new-symbol decl-type name node
+                               js2-current-script-or-fn)))
      ((= decl-type js2-LP)
       (if symbol
           ;; must be duplicate parameter. Second parameter hides the

commit 6e2677e9891d56ca9c64048dc4302b117ab32c86
Author: Szymon Nowak <address@hidden>
Date:   Mon Mar 14 21:48:29 2011 +0100

    Fix 'Warning: Bug in js2-mode: it forgets to call 'run-mode-hooks''

diff --git a/js2-mode.el b/js2-mode.el
index 64ce5b8..042ffbe 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10439,7 +10439,10 @@ If so, we don't ever want to use bounce-indent."
         js2-mode-buffer-dirty-p t
         js2-mode-parsing nil)
   (js2-reparse)
-  (run-hooks 'js2-mode-hook))
+
+  (if (fboundp 'run-mode-hooks)
+      (run-mode-hooks 'js2-mode-hook)
+    (run-hooks 'js2-mode-hook)))
 
 (defun js2-mode-exit ()
   "Exit `js2-mode' and clean up."

commit bcafe8294b55e3e17bbd99381b395ddc37e1e838
Author: Chris Wanstrath <address@hidden>
Date:   Fri Mar 4 23:24:55 2011 -0800

    revert f7de20f4c11cb49605551fc6dc0b778803f0fd38

diff --git a/coffee-mode.el b/coffee-mode.el
index 9523c45..2334043 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -589,7 +589,6 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; indentation
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'coffee-indent-line)
-  (setq coffee-tab-width tab-width) ;; Just in case...
 
   ;; imenu
   (make-local-variable 'imenu-create-index-function)

commit 40a5bf1b51b8b0508902db515e2683016f3bb075
Author: Chris Wanstrath <address@hidden>
Date:   Fri Mar 4 23:22:37 2011 -0800

    comment-start is buffer local. fixes #10

diff --git a/coffee-mode.el b/coffee-mode.el
index f08cbee..9523c45 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -580,6 +580,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; perl style comment: "# ..."
   (modify-syntax-entry ?# "< b" coffee-mode-syntax-table)
   (modify-syntax-entry ?\n "> b" coffee-mode-syntax-table)
+  (make-local-variable 'comment-start)
   (setq comment-start "#")
 
   ;; single quote strings

commit 2e96b3cd99d263a23c8f3524b11bfcc2f6f889cc
Author: Ryan Koopmans <address@hidden>
Date:   Mon Feb 14 13:00:25 2011 -0800

    Limit assignment fontlocking to property names.

diff --git a/coffee-mode.el b/coffee-mode.el
index 05176ba..f08cbee 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -238,7 +238,7 @@ path."
 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| 
\\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
 ;; Assignment
-(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\)[:=]")
+(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
 ;; Lambda
 (defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")

commit 7803688b40e32bcd176000a5f011bf0e2aabda85
Author: Ryan Koopmans <address@hidden>
Date:   Thu Dec 23 10:38:59 2010 -0800

    Until and loop are keywords.

diff --git a/coffee-mode.el b/coffee-mode.el
index acedea6..05176ba 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -257,7 +257,7 @@ path."
       '("if" "else" "new" "return" "try" "catch"
         "finally" "throw" "break" "continue" "for" "in" "while"
         "delete" "instanceof" "typeof" "switch" "super" "extends"
-        "class"))
+        "class" "until" "loop"))
 
 ;; Reserved keywords either by JS or CS.
 (defvar coffee-js-reserved

commit f4597a051d823346f67f30e06910efea530aacf0
Author: Daisuke Murase <address@hidden>
Date:   Fri Mar 4 20:08:44 2011 +0900

    Fixed inf loop in coffee-previous-indent

diff --git a/coffee-mode.el b/coffee-mode.el
index e767e58..acedea6 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -469,7 +469,7 @@ For detail, see `comment-dwim'."
     (if (bobp)
         0
       (progn
-        (while (coffee-line-empty-p) (forward-line -1))
+        (while (and (coffee-line-empty-p) (not (bobp))) (forward-line -1))
         (current-indentation)))))
 
 (defun coffee-line-empty-p ()

commit 7eda082b652be8c525192257c1912626b2ac7eae
Author: Dmitry Gutov <address@hidden>
Date:   Sat Feb 26 21:00:01 2011 +0300

    `js2-imenu-fn-type-map' should be local to `js2-browse-postprocess-chains'

diff --git a/js2-mode.el b/js2-mode.el
index 64ce5b8..9defd18 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1264,7 +1264,6 @@ First match-group is the leading whitespace.")
 (js2-deflocal js2-mode-deferred-properties nil "Private variable")
 (js2-deflocal js2-imenu-recorder nil "Private variable")
 (js2-deflocal js2-imenu-function-map nil "Private variable")
-(js2-deflocal js2-imenu-fn-type-map nil "Private variable")
 
 (defvar js2-paragraph-start
   "\\(@[a-zA-Z]+\\>\\|$\\)")
@@ -6886,7 +6885,8 @@ NODE must be `js2-function-node'."
   "Modify function-declaration name chains after parsing finishes.
 Some of the information is only available after the parse tree is complete.
 For instance, following a 'this' reference requires a parent function node."
-  (let (result head fn fn-type parent-chain p elem parent)
+  (let ((js2-imenu-fn-type-map (make-hash-table :test 'eq))
+        result head fn fn-type parent-chain p elem parent)
     (dolist (chain chains)
       ;; examine the head of each node to get its defining scope
       (setq head (car chain))
@@ -6904,9 +6904,7 @@ For instance, following a 'this' reference requires a 
parent function node."
          ;; variable assigned a function expression
          (t (setq fn (js2-node-parent-script-or-fn head))))
         (when fn
-          (if js2-imenu-fn-type-map
-              (setq fn-type (gethash fn js2-imenu-fn-type-map))
-            (setq js2-imenu-fn-type-map (make-hash-table :test 'eq)))
+          (setq fn-type (gethash fn js2-imenu-fn-type-map))
           (unless fn-type
             (setq fn-type
                   (cond ((js2-nested-function-p fn) 'skip)
@@ -7309,7 +7307,6 @@ leaving a statement, an expression, or a function 
definition."
             js2-parsed-warnings nil
             js2-imenu-recorder nil
             js2-imenu-function-map nil
-            js2-imenu-fn-type-map nil
             js2-label-set nil)
       (js2-init-scanner)
       (setq ast (js2-with-unmodifying-text-property-changes
@@ -11441,8 +11438,7 @@ destroying the region selection."
     (prog1
         (js2-build-imenu-index)
       (setq js2-imenu-recorder nil
-            js2-imenu-function-map nil
-            js2-imenu-fn-type-map nil))))
+            js2-imenu-function-map nil))))
 
 (defun js2-mode-find-tag ()
   "Replacement for `find-tag-default'.

commit 8a3d6f5378500bb394d0e555bc1473ea6279f0d1
Author: Nick Parker <address@hidden>
Date:   Thu Dec 16 20:03:45 2010 -0600

    Updating coffee-repl to pop-to-buffer using the name '*CoffeeREPL*' instead 
of '*CoffeeScript*', it wasn't switching to the repl previously

diff --git a/coffee-mode.el b/coffee-mode.el
index 23af2b8..e767e58 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -154,7 +154,7 @@ path."
      (apply 'make-comint "CoffeeREPL"
             coffee-command nil coffee-args-repl)))
 
-  (pop-to-buffer "*CoffeeScript*"))
+  (pop-to-buffer "*CoffeeREPL*"))
 
 (defun coffee-compile-file ()
   "Compiles and saves the current file to disk. Doesn't open in a buffer.."

commit 625d37928c3a68c27a7b0b2cbd2d8abb099f3cc9
Merge: b874bf4 79bad0a
Author: Chris Wanstrath <address@hidden>
Date:   Mon Feb 21 19:04:23 2011 -0800

    Merge branch 'master' of https://github.com/sstephenson/coffee-mode into 
sstephenson-master


commit 550693de5410011d79555f04092e481710cf204b
Author: mooz <address@hidden>
Date:   Mon Feb 21 12:44:47 2011 +0900

    corrected documentation of multi-line variable declaration

diff --git a/README.md b/README.md
index 04d5dd1..3f863f1 100644
--- a/README.md
+++ b/README.md
@@ -48,8 +48,8 @@ When js2-consistent-level-indent-inner-bracket-p is nil
                        return validate(v);
                    });
 
-Fixed ugly indentation with multi-line variable declaration
------------------------------------------------------------
+Pretty multi-line variable declaration
+--------------------------------------
 
 In original js2-mode.el,
 
@@ -57,7 +57,7 @@ In original js2-mode.el,
     bar = 20,
     baz = 30;
 
-In this js2-mode.el,
+In this js2-mode.el, when the value `js2-use-ast-for-indentation-p` is non-nil 
(default nil),
 
     var foo = 10,
         bar = 20,

commit 41021bd85a4c40fe293ceb8fa16aac954b4f3df4
Author: mooz <address@hidden>
Date:   Sun Feb 20 14:56:36 2011 +0900

    print catch clause correctly.

diff --git a/js2-mode.el b/js2-mode.el
index 8e8414c..64ce5b8 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2718,7 +2718,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
         (guard-kwd (js2-catch-node-guard-kwd n))
         (guard-expr (js2-catch-node-guard-expr n)))
     (insert " catch (")
-    (js2-print-ast (js2-catch-node-var-name n) 0)
+    (js2-print-ast (js2-catch-node-param n) 0)
     (when guard-kwd
       (insert " if ")
       (js2-print-ast guard-expr 0))

commit 1303babda4c95f1ff1a39b8908f33c69cf500b0d
Author: mooz <address@hidden>
Date:   Sun Feb 20 14:51:57 2011 +0900

    Accept destructuring form in catch clause

diff --git a/js2-mode.el b/js2-mode.el
index 7b45348..8e8414c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2690,14 +2690,14 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
             (:constructor make-js2-catch-node (&key (type js2-CATCH)
                                                     (pos js2-ts-cursor)
                                                     len
-                                                    var-name
+                                                    param
                                                     guard-kwd
                                                     guard-expr
                                                     block
                                                     lp
                                                     rp)))
   "AST node for a catch clause."
-  var-name    ; a `js2-name-node'
+  param       ; destructuring form or simple name node
   guard-kwd   ; relative buffer position of "if" in "catch (x if ...)"
   guard-expr  ; catch condition, a `js2-node'
   block       ; statements, a `js2-block-node'
@@ -2708,7 +2708,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
 (put 'cl-struct-js2-catch-node 'js2-printer 'js2-print-catch-node)
 
 (defun js2-visit-catch-node (n v)
-  (js2-visit-ast (js2-catch-node-var-name n) v)
+  (js2-visit-ast (js2-catch-node-param n) v)
   (when (js2-catch-node-guard-kwd n)
     (js2-visit-ast (js2-catch-node-guard-expr n) v))
   (js2-visit-ast (js2-catch-node-block n) v))
@@ -7416,9 +7416,10 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
     (let (leftpos)
       (js2-define-symbol decl-type (js2-name-node-name node)
                          node ignore-not-in-block)
-      (js2-set-face (setq leftpos (js2-node-abs-pos node))
-                    (+ leftpos (js2-node-len node))
-                    face 'record)))
+      (when face
+        (js2-set-face (setq leftpos (js2-node-abs-pos node))
+                      (+ leftpos (js2-node-len node))
+                      face 'record))))
    ((js2-object-node-p node)
     (dolist (elem (js2-object-node-elems node))
       (js2-define-destruct-symbols
@@ -7979,7 +7980,7 @@ Parses for, for-in, and for each-in statements."
         finally-block
         saw-default-catch
         peek
-        var-name
+        param
         catch-cond
         catch-node
         guard-kwd
@@ -8007,10 +8008,21 @@ Parses for, for-in, and for each-in statements."
             (js2-report-error "msg.catch.unreachable"))
         (if (js2-must-match js2-LP "msg.no.paren.catch")
             (setq lp (- js2-token-beg catch-pos)))
-        (js2-must-match js2-NAME "msg.bad.catchcond")
         (js2-push-scope (make-js2-scope))
-        (setq var-name (js2-create-name-node))
-        (js2-define-symbol js2-LET (js2-name-node-name var-name) var-name t)
+        (let ((tt (js2-peek-token)))
+          (cond
+           ;; destructuring pattern
+           ;;     catch ({ message, file }) { ... }
+           ((or (= tt js2-LB) (= tt js2-LC))
+            (setq param
+                  (js2-define-destruct-symbols (js2-parse-primary-expr-lhs)
+                                               js2-LET nil)))
+           ;; simple name
+           (t
+            (js2-must-match js2-NAME "msg.bad.catchcond")
+            (setq param (js2-create-name-node))
+            (js2-define-symbol js2-LET js2-ts-string param))))
+        ;; pattern guard
         (if (js2-match-token js2-IF)
             (setq guard-kwd (- js2-token-beg catch-pos)
                   catch-cond (js2-parse-expr))
@@ -8021,7 +8033,7 @@ Parses for, for-in, and for each-in statements."
         (setq block (js2-parse-statements)
               try-end (js2-node-end block)
               catch-node (make-js2-catch-node :pos catch-pos
-                                              :var-name var-name
+                                              :param param
                                               :guard-expr catch-cond
                                               :guard-kwd guard-kwd
                                               :block block
@@ -8032,7 +8044,7 @@ Parses for, for-in, and for each-in statements."
             (setq try-end js2-token-beg))
         (setf (js2-node-len block) (- try-end (js2-node-pos block))
               (js2-node-len catch-node) (- try-end catch-pos))
-        (js2-node-add-children catch-node var-name catch-cond block)
+        (js2-node-add-children catch-node param catch-cond block)
         (push catch-node catch-blocks)))
      ((/= peek js2-FINALLY)
       (js2-must-match js2-FINALLY "msg.try.no.catchfinally"

commit 81e003ac96aa48f1efe77f4b9d415790902ac5b6
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 20 03:30:40 2011 +0300

    Fix js2-nested-function-p for when node is `js2-ast-root'

diff --git a/js2-mode.el b/js2-mode.el
index 96b25e5..7b45348 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -4652,10 +4652,11 @@ If NODE is the ast-root, returns nil."
 
 (defsubst js2-nested-function-p (node)
   "Return t if NODE is a nested function, or is inside a nested function."
-  (js2-function-node-p (if (js2-function-node-p node)
-                           (js2-node-parent-script-or-fn node)
-                         (js2-node-parent-script-or-fn
-                          (js2-node-parent-script-or-fn node)))))
+  (unless (js2-ast-root-p node)
+    (js2-function-node-p (if (js2-function-node-p node)
+                             (js2-node-parent-script-or-fn node)
+                           (js2-node-parent-script-or-fn
+                            (js2-node-parent-script-or-fn node))))))
 
 (defsubst js2-function-param-node-p (node)
   "Return non-nil if NODE is a param node of a `js2-function-node'."

commit e15463d4c9fd3b8ea4e7487bb617c713f698e44d
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 20 00:08:33 2011 +0300

    Detect anonymous wrapper functions more reliably

diff --git a/js2-mode.el b/js2-mode.el
index daea4ab..96b25e5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1264,6 +1264,7 @@ First match-group is the leading whitespace.")
 (js2-deflocal js2-mode-deferred-properties nil "Private variable")
 (js2-deflocal js2-imenu-recorder nil "Private variable")
 (js2-deflocal js2-imenu-function-map nil "Private variable")
+(js2-deflocal js2-imenu-fn-type-map nil "Private variable")
 
 (defvar js2-paragraph-start
   "\\(@[a-zA-Z]+\\>\\|$\\)")
@@ -6867,11 +6868,24 @@ that it's an external variable, which must also be in 
the top-level scope."
       (js2-ast-root-p defining-scope))
      (t t))))
 
+(defsubst js2-anonymous-wrapper-fn-p (node)
+  "Returns t if NODE is an anonymous function that's invoked immediately.
+NODE must be `js2-function-node'."
+  (let ((parent (js2-node-parent node)))
+    (and (js2-paren-node-p parent)
+         ;; (function(){...})();
+         (or (js2-call-node-p (setq parent (js2-node-parent parent)))
+             ;; (function(){...}).call(this);
+             (and (js2-prop-get-node-p parent)
+                  (member (js2-name-node-name (js2-prop-get-node-right parent))
+                          '("call" "apply"))
+                  (js2-call-node-p (js2-node-parent parent)))))))
+
 (defun js2-browse-postprocess-chains (chains)
   "Modify function-declaration name chains after parsing finishes.
 Some of the information is only available after the parse tree is complete.
 For instance, following a 'this' reference requires a parent function node."
-  (let (result head fn parent-chain p elem parent)
+  (let (result head fn fn-type parent-chain p elem parent)
     (dolist (chain chains)
       ;; examine the head of each node to get its defining scope
       (setq head (car chain))
@@ -6888,17 +6902,25 @@ For instance, following a 'this' reference requires a 
parent function node."
           (setq fn (js2-node-parent-script-or-fn parent)))
          ;; variable assigned a function expression
          (t (setq fn (js2-node-parent-script-or-fn head))))
-        (unless (or (null fn) (js2-nested-function-p fn))
-          ;; if the parent function is found, and it's not nested,
-          ;; look it up in function-map.
-          (if (setq parent-chain (and js2-imenu-function-map
-                                      (gethash fn js2-imenu-function-map)))
-              ;; prefix parent fn qname, which is the
-              ;; parent-chain sans tail, to this chain.
-              (push (append (butlast parent-chain) chain) result)
-            ;; parent function is not nested, and not in function-map
-            ;; => it's anonymous top-level wrapper, discard.
-            (push chain result)))))
+        (when fn
+          (if js2-imenu-fn-type-map
+              (setq fn-type (gethash fn js2-imenu-fn-type-map))
+            (setq js2-imenu-fn-type-map (make-hash-table :test 'eq)))
+          (unless fn-type
+            (setq fn-type
+                  (cond ((js2-nested-function-p fn) 'skip)
+                        ((setq parent-chain
+                               (gethash fn js2-imenu-function-map))
+                         'named)
+                        ((js2-anonymous-wrapper-fn-p fn) 'anon)
+                        (t 'skip)))
+            (puthash fn fn-type js2-imenu-fn-type-map))
+          (case fn-type
+            ('anon (push chain result)) ; anonymous top-level wrapper
+            ('named                     ; top-level named function
+             ;; prefix parent fn qname, which is
+             ;; parent-chain sans last elem, to this chain.
+             (push (append (butlast parent-chain) chain) result))))))
     ;; finally replace each node in each chain with its name.
     (dolist (chain result)
       (setq p chain)
@@ -7286,6 +7308,7 @@ leaving a statement, an expression, or a function 
definition."
             js2-parsed-warnings nil
             js2-imenu-recorder nil
             js2-imenu-function-map nil
+            js2-imenu-fn-type-map nil
             js2-label-set nil)
       (js2-init-scanner)
       (setq ast (js2-with-unmodifying-text-property-changes
@@ -11405,7 +11428,8 @@ destroying the region selection."
     (prog1
         (js2-build-imenu-index)
       (setq js2-imenu-recorder nil
-            js2-imenu-function-map nil))))
+            js2-imenu-function-map nil
+            js2-imenu-fn-type-map nil))))
 
 (defun js2-mode-find-tag ()
   "Replacement for `find-tag-default'.

commit 86ef0c89c7c97df887a83303f76cd6113e6d8889
Author: Dmitry Gutov <address@hidden>
Date:   Sat Feb 19 00:05:37 2011 +0300

    Declare exception symbol in the catch block

diff --git a/js2-mode.el b/js2-mode.el
index b66a9f0..daea4ab 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7984,7 +7984,9 @@ Parses for, for-in, and for each-in statements."
         (if (js2-must-match js2-LP "msg.no.paren.catch")
             (setq lp (- js2-token-beg catch-pos)))
         (js2-must-match js2-NAME "msg.bad.catchcond")
+        (js2-push-scope (make-js2-scope))
         (setq var-name (js2-create-name-node))
+        (js2-define-symbol js2-LET (js2-name-node-name var-name) var-name t)
         (if (js2-match-token js2-IF)
             (setq guard-kwd (- js2-token-beg catch-pos)
                   catch-cond (js2-parse-expr))
@@ -8001,6 +8003,7 @@ Parses for, for-in, and for each-in statements."
                                               :block block
                                               :lp lp
                                               :rp rp))
+        (js2-pop-scope)
         (if (js2-must-match js2-RC "msg.no.brace.after.body")
             (setq try-end js2-token-beg))
         (setf (js2-node-len block) (- try-end (js2-node-pos block))

commit 772def80337ba1bf30028216214014454a2d43c0
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 18 22:35:03 2011 +0300

    Fix byte-compile warnings

diff --git a/js2-mode.el b/js2-mode.el
index 9e5fd06..b66a9f0 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2024,6 +2024,10 @@ Returns nil if element is not found in the list."
   "Signal an error when we encounter an unexpected code path."
   (error "failed assertion"))
 
+(defsubst js2-record-text-property (beg end prop value)
+  "Record a text property to set when parsing finishes."
+  (push (list beg end prop value) js2-mode-deferred-properties))
+
 ;; I'd like to associate errors with nodes, but for now the
 ;; easiest thing to do is get the context info from the last token.
 (defsubst js2-record-parse-error (msg &optional arg pos len)
@@ -6236,10 +6240,6 @@ FACE is the face to fontify with."
                                     point-entered nil
                                     c-in-sws nil)))
 
-(defsubst js2-record-text-property (beg end prop value)
-  "Record a text property to set when parsing finishes."
-  (push (list beg end prop value) js2-mode-deferred-properties))
-
 (defconst js2-ecma-global-props
   (concat "^"
           (regexp-opt
@@ -6630,10 +6630,11 @@ of a simple name.  Called before EXPR has a parent 
node."
 (defun js2-record-name-node (node)
   "Saves NODE to `js2-recorded-identifiers' to check for undeclared variables
 later. NODE must be a name node."
-  (push (list node js2-current-scope
-              (setq leftpos (js2-node-abs-pos node))
-              (setq end (+ leftpos (js2-node-len node))))
-        js2-recorded-identifiers))
+  (let (leftpos end)
+    (push (list node js2-current-scope
+                (setq leftpos (js2-node-abs-pos node))
+                (setq end (+ leftpos (js2-node-len node))))
+          js2-recorded-identifiers)))
 
 (defun js2-highlight-undeclared-vars ()
   "After entire parse is finished, look for undeclared variable references.
@@ -6870,7 +6871,7 @@ that it's an external variable, which must also be in the 
top-level scope."
   "Modify function-declaration name chains after parsing finishes.
 Some of the information is only available after the parse tree is complete.
 For instance, following a 'this' reference requires a parent function node."
-  (let (result head fn parent-chain p elem)
+  (let (result head fn parent-chain p elem parent)
     (dolist (chain chains)
       ;; examine the head of each node to get its defining scope
       (setq head (car chain))

commit cfb3cdf1ef3868f3cc2d57094ae55bc24dbd5fc3
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 18 21:46:22 2011 +0300

    Defer removing syntax-table text property until parsing is done
    
    Resolves problem with large files that have a regex literal that
    confuses the syntax table (like jquery.js).
    Previously, if parsing was interrupted by user input, such regex
    in a not-yet-parsed part of file broke `parse-partial-sexp' and,
    consequently, `js2-enter-key'.

diff --git a/js2-mode.el b/js2-mode.el
index b087b94..9e5fd06 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -5992,7 +5992,7 @@ corresponding number.  Otherwise return -1."
             js2-ts-regexp-flags (js2-collect-string flags)
             js2-token-end js2-ts-cursor)
       ;; tell `parse-partial-sexp' to ignore this range of chars
-      (put-text-property js2-token-beg js2-token-end 'syntax-class '(2)))))
+      (js2-record-text-property js2-token-beg js2-token-end 'syntax-class 
'(2)))))
 
 (defun js2-get-first-xml-token ()
   (setq js2-ts-xml-open-tags-count 0
@@ -7059,7 +7059,7 @@ is only true until the node is added to its parent; i.e., 
while parsing."
                        'font-lock-comment-face))
     (when (memq js2-ts-comment-type '(html preprocessor))
       ;; Tell cc-engine the bounds of the comment.
-      (put-text-property js2-token-beg (1- js2-token-end) 'c-in-sws t))))
+      (js2-record-text-property js2-token-beg (1- js2-token-end) 'c-in-sws 
t))))
 
 ;; This function is called depressingly often, so it should be fast.
 ;; Most of the time it's looking at the same token it peeked before.
@@ -9260,7 +9260,7 @@ array-literals, array comprehensions and regular 
expressions."
                                 :value js2-ts-string
                                 :flags flags)
         (js2-set-face px-pos js2-ts-cursor 'font-lock-string-face 'record)
-        (put-text-property px-pos js2-ts-cursor 'syntax-table '(2))))
+        (js2-record-text-property px-pos js2-ts-cursor 'syntax-table '(2))))
      ((or (= tt js2-NULL)
           (= tt js2-THIS)
           (= tt js2-FALSE)
@@ -10480,7 +10480,6 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
           (when (or js2-mode-buffer-dirty-p force)
             (js2-remove-overlays)
             (js2-with-unmodifying-text-property-changes
-              (remove-text-properties (point-min) (point-max) '(syntax-table))
               (setq js2-mode-buffer-dirty-p nil
                     js2-mode-fontifications nil
                     js2-mode-deferred-properties nil
@@ -10492,8 +10491,11 @@ buffer will only rebuild its `js2-mode-ast' if the 
buffer is dirty."
                      (setq interrupted-p
                            (catch 'interrupted
                              (setq js2-mode-ast (js2-parse))
-                             (when (plusp js2-highlight-level)
-                               (js2-mode-fontify-regions))
+                             ;; if parsing is interrupted, comments and regex
+                             ;; literals stay ignored by `parse-partial-sexp'
+                             (remove-text-properties (point-min) (point-max)
+                                                     '(syntax-table))
+                             (js2-mode-apply-deferred-properties)
                              (js2-mode-remove-suppressed-warnings)
                              (js2-mode-show-warnings)
                              (js2-mode-show-errors)
@@ -10589,15 +10591,16 @@ Defaults to point."
         for o in (overlays-at pos)
         thereis (overlay-get o 'js2-error)))
 
-(defun js2-mode-fontify-regions ()
-  "Apply fontifications recorded during parsing."
-  ;; We defer clearing faces as long as possible to eliminate flashing.
-  (js2-clear-face (point-min) (point-max))
-  ;; have to reverse the recorded fontifications so that errors and
-  ;; warnings overwrite the normal fontifications
-  (dolist (f (nreverse js2-mode-fontifications))
-    (put-text-property (first f) (second f) 'face (third f)))
-  (setq js2-mode-fontifications nil)
+(defun js2-mode-apply-deferred-properties ()
+  "Apply fontifications and other text properties recorded during parsing."
+  (when (plusp js2-highlight-level)
+    ;; We defer clearing faces as long as possible to eliminate flashing.
+    (js2-clear-face (point-min) (point-max))
+    ;; Have to reverse the recorded fontifications list so that errors
+    ;; and warnings overwrite the normal fontifications.
+    (dolist (f (nreverse js2-mode-fontifications))
+      (put-text-property (first f) (second f) 'face (third f)))
+    (setq js2-mode-fontifications nil))
   (dolist (p js2-mode-deferred-properties)
     (apply #'put-text-property p))
   (setq js2-mode-deferred-properties nil))

commit 23f5fa60af7dc8dfdaccecfd663833cfacab1101
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 18 16:39:06 2011 +0300

    Remove unnecessary checks

diff --git a/js2-mode.el b/js2-mode.el
index 494730c..b087b94 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2585,8 +2585,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
 (put 'cl-struct-js2-return-node 'js2-printer 'js2-print-return-node)
 
 (defun js2-visit-return-node (n v)
-  (if (js2-return-node-retval n)
-      (js2-visit-ast (js2-return-node-retval n) v)))
+  (js2-visit-ast (js2-return-node-retval n) v))
 
 (defun js2-print-return-node (n i)
   (insert (js2-make-pad i) "return")
@@ -2621,8 +2620,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
 (defun js2-visit-if-node (n v)
   (js2-visit-ast (js2-if-node-condition n) v)
   (js2-visit-ast (js2-if-node-then-part n) v)
-  (if (js2-if-node-else-part n)
-      (js2-visit-ast (js2-if-node-else-part n) v)))
+  (js2-visit-ast (js2-if-node-else-part n) v))
 
 (defun js2-print-if-node (n i)
   (let ((pad (js2-make-pad i))
@@ -2665,8 +2663,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
   (js2-visit-ast (js2-try-node-try-block n) v)
   (dolist (clause (js2-try-node-catch-clauses n))
     (js2-visit-ast clause v))
-  (if (js2-try-node-finally-block n)
-      (js2-visit-ast (js2-try-node-finally-block n) v)))
+  (js2-visit-ast (js2-try-node-finally-block n) v))
 
 (defun js2-print-try-node (n i)
   (let ((pad (js2-make-pad i))
@@ -2795,8 +2792,7 @@ NAME can be a lisp symbol or string.  SYMBOL is a 
`js2-symbol'."
 (put 'cl-struct-js2-case-node 'js2-printer 'js2-print-case-node)
 
 (defun js2-visit-case-node (n v)
-  (if (js2-case-node-expr n)  ; nil for default: case
-      (js2-visit-ast (js2-case-node-expr n) v))
+  (js2-visit-ast (js2-case-node-expr n) v)
   (js2-visit-block n v))
 
 (defun js2-print-case-node (n i)
@@ -2942,9 +2938,7 @@ NODE is a `js2-labels-node'.  LABEL is an identifier."
   target) ; target js2-labels-node or loop/switch statement
 
 (defun js2-visit-jump-node (n v)
-  ;; we don't visit the target, since it's a back-link
-  (if (js2-jump-node-label n)
-      (js2-visit-ast (js2-jump-node-label n) v)))
+  (js2-visit-ast (js2-jump-node-label n) v))
 
 (defstruct (js2-break-node
             (:include js2-jump-node)
@@ -3025,12 +3019,10 @@ The `params' field is a lisp list of nodes.  Each node 
is either a simple
 (put 'cl-struct-js2-function-node 'js2-printer 'js2-print-function-node)
 
 (defun js2-visit-function-node (n v)
-  (if (js2-function-node-name n)
-      (js2-visit-ast (js2-function-node-name n) v))
+  (js2-visit-ast (js2-function-node-name n) v)
   (dolist (p (js2-function-node-params n))
     (js2-visit-ast p v))
-  (when (js2-function-node-body n)
-    (js2-visit-ast (js2-function-node-body n) v)))
+  (js2-visit-ast (js2-function-node-body n) v))
 
 (defun js2-print-function-node (n i)
   (let ((pad (js2-make-pad i))
@@ -3130,8 +3122,7 @@ The type field will be js2-CONST for a const decl."
 
 (defun js2-visit-var-init-node (n v)
   (js2-visit-ast (js2-var-init-node-target n) v)
-  (if (js2-var-init-node-initializer n)
-      (js2-visit-ast (js2-var-init-node-initializer n) v)))
+  (js2-visit-ast (js2-var-init-node-initializer n) v))
 
 (defun js2-print-var-init-node (n i)
   (let ((pad (js2-make-pad i))
@@ -3198,10 +3189,8 @@ The type field inherited from `js2-node' holds the 
operator."
 (put 'cl-struct-js2-infix-node 'js2-printer 'js2-print-infix-node)
 
 (defun js2-visit-infix-node (n v)
-  (when (js2-infix-node-left n)
-    (js2-visit-ast (js2-infix-node-left n) v))
-  (when (js2-infix-node-right n)
-    (js2-visit-ast (js2-infix-node-right n) v)))
+  (js2-visit-ast (js2-infix-node-left n) v)
+  (js2-visit-ast (js2-infix-node-right n) v))
 
 (defconst js2-operator-tokens
   (let ((table (make-hash-table :test 'eq))
@@ -3339,10 +3328,8 @@ Note that a let declaration such as let x=6, y=7 is a 
`js2-var-decl-node'."
 (put 'cl-struct-js2-let-node 'js2-printer 'js2-print-let-node)
 
 (defun js2-visit-let-node (n v)
-  (when (js2-let-node-vars n)
-    (js2-visit-ast (js2-let-node-vars n) v))
-  (when (js2-let-node-body n)
-    (js2-visit-ast (js2-let-node-body n) v)))
+  (js2-visit-ast (js2-let-node-vars n) v)
+  (js2-visit-ast (js2-let-node-body n) v))
 
 (defun js2-print-let-node (n i)
   (insert (js2-make-pad i) "let (")
@@ -3403,8 +3390,7 @@ The node type is set to js2-NULL, js2-THIS, etc.")
   (js2-visit-ast (js2-new-node-target n) v)
   (dolist (arg (js2-new-node-args n))
     (js2-visit-ast arg v))
-  (when (js2-new-node-initializer n)
-    (js2-visit-ast (js2-new-node-initializer n) v)))
+  (js2-visit-ast (js2-new-node-initializer n) v))
 
 (defun js2-print-new-node (n i)
   (insert (js2-make-pad i) "new ")
@@ -3521,8 +3507,7 @@ You can tell the quote type by looking at the first 
character."
 
 (defun js2-visit-array-node (n v)
   (dolist (e (js2-array-node-elems n))
-    (when e  ; can be nil, e.g. [a, ,b]
-      (js2-visit-ast e v))))
+    (js2-visit-ast e v)))
 
 (defun js2-print-array-node (n i)
   (insert (js2-make-pad i) "[")
@@ -3614,10 +3599,8 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
 (put 'cl-struct-js2-prop-get-node 'js2-printer 'js2-print-prop-get-node)
 
 (defun js2-visit-prop-get-node (n v)
-  (when (js2-prop-get-node-left n)
-    (js2-visit-ast (js2-prop-get-node-left n) v))
-  (when (js2-prop-get-node-right n)
-    (js2-visit-ast (js2-prop-get-node-right n) v)))
+  (js2-visit-ast (js2-prop-get-node-left n) v)
+  (js2-visit-ast (js2-prop-get-node-right n) v))
 
 (defun js2-print-prop-get-node (n i)
   (insert (js2-make-pad i))
@@ -3645,10 +3628,8 @@ property `GETTER_SETTER' set to js2-GET or js2-SET. ")
 (put 'cl-struct-js2-elem-get-node 'js2-printer 'js2-print-elem-get-node)
 
 (defun js2-visit-elem-get-node (n v)
-  (when (js2-elem-get-node-target n)
-    (js2-visit-ast (js2-elem-get-node-target n) v))
-  (when (js2-elem-get-node-element n)
-    (js2-visit-ast (js2-elem-get-node-element n) v)))
+  (js2-visit-ast (js2-elem-get-node-target n) v)
+  (js2-visit-ast (js2-elem-get-node-element n) v))
 
 (defun js2-print-elem-get-node (n i)
   (insert (js2-make-pad i))
@@ -3762,8 +3743,7 @@ as opposed to required parens such as those enclosing an 
if-conditional."
   (js2-visit-ast (js2-array-comp-node-result n) v)
   (dolist (l (js2-array-comp-node-loops n))
     (js2-visit-ast l v))
-  (if (js2-array-comp-node-filter n)
-      (js2-visit-ast (js2-array-comp-node-filter n) v)))
+  (js2-visit-ast (js2-array-comp-node-filter n) v))
 
 (defun js2-print-array-comp-node (n i)
   (let ((pad (js2-make-pad i))
@@ -3949,10 +3929,8 @@ expression."
 (put 'cl-struct-js2-xml-prop-ref-node 'js2-printer 
'js2-print-xml-prop-ref-node)
 
 (defun js2-visit-xml-prop-ref-node (n v)
-  (if (js2-xml-prop-ref-node-namespace n)
-      (js2-visit-ast (js2-xml-prop-ref-node-namespace n) v))
-  (if (js2-xml-prop-ref-node-propname n)
-      (js2-visit-ast (js2-xml-prop-ref-node-propname n) v)))
+  (js2-visit-ast (js2-xml-prop-ref-node-namespace n) v)
+  (js2-visit-ast (js2-xml-prop-ref-node-propname n) v))
 
 (defun js2-print-xml-prop-ref-node (n i)
   (insert (js2-make-pad i))
@@ -4001,10 +3979,8 @@ end of the index expression."
 (put 'cl-struct-js2-xml-elem-ref-node 'js2-printer 
'js2-print-xml-elem-ref-node)
 
 (defun js2-visit-xml-elem-ref-node (n v)
-  (if (js2-xml-elem-ref-node-namespace n)
-      (js2-visit-ast (js2-xml-elem-ref-node-namespace n) v))
-  (if (js2-xml-elem-ref-node-expr n)
-      (js2-visit-ast (js2-xml-elem-ref-node-expr n) v)))
+  (js2-visit-ast (js2-xml-elem-ref-node-namespace n) v)
+  (js2-visit-ast (js2-xml-elem-ref-node-expr n) v))
 
 (defun js2-print-xml-elem-ref-node (n i)
   (insert (js2-make-pad i))

commit b38c19ed6013b4418a5751d0de0670c8716a345e
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 18 16:23:08 2011 +0300

    Fix js2-time

diff --git a/js2-mode.el b/js2-mode.el
index 20381f3..494730c 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2005,8 +2005,8 @@ Returns nil if element is not found in the list."
            ,delta)
        ,form
        (/ (truncate (* (- (float-time (current-time))
-                          (float-time ,beg)))
-                    10000)
+                          (float-time ,beg))
+                       10000))
           10000.0))))
 
 (defsubst js2-same-line (pos)

commit 8c7bd5a874a26c733f922181b22918f4a80dc594
Author: Dmitry Gutov <address@hidden>
Date:   Thu Feb 17 23:41:30 2011 +0300

    Don't visit empty nodes
    
    That fixes js2-mode-forward-sexp when the buffer has parsing errors

diff --git a/js2-mode.el b/js2-mode.el
index 4c191e0..20381f3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -2149,23 +2149,24 @@ callback is called immediately with a non-nil END-P 
argument.
 
 The node traversal is approximately lexical-order, although there
 are currently no guarantees around this."
-  (let ((vfunc (get (aref node 0) 'js2-visitor)))
-    ;; visit the node
-    (when  (funcall callback node nil)
-      ;; visit the kids
-      (cond
-       ((eq vfunc 'js2-visit-none)
-        nil)                            ; don't even bother calling it
-       ;; Each AST node type has to define a `js2-visitor' function
-       ;; that takes a node and a callback, and calls `js2-visit-ast'
-       ;; on each child of the node.
-       (vfunc
-        (funcall vfunc node callback))
-       (t
-        (error "%s does not define a visitor-traversal function"
-               (aref node 0)))))
-    ;; call the end-visit
-    (funcall callback node t)))
+  (if node
+    (let ((vfunc (get (aref node 0) 'js2-visitor)))
+      ;; visit the node
+      (when  (funcall callback node nil)
+        ;; visit the kids
+        (cond
+         ((eq vfunc 'js2-visit-none)
+          nil)                            ; don't even bother calling it
+         ;; Each AST node type has to define a `js2-visitor' function
+         ;; that takes a node and a callback, and calls `js2-visit-ast'
+         ;; on each child of the node.
+         (vfunc
+          (funcall vfunc node callback))
+         (t
+          (error "%s does not define a visitor-traversal function"
+                 (aref node 0)))))
+      ;; call the end-visit
+      (funcall callback node t))))
 
 (defstruct (js2-node
             (:constructor nil))  ; abstract

commit 655ad4a630189a4b827863811fad5155dfe8f5ee
Author: mooz <address@hidden>
Date:   Thu Feb 17 13:01:39 2011 +0900

    window

diff --git a/js2-mode.el b/js2-mode.el
index a8784b4..4c191e0 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -126,7 +126,7 @@
             UserDataHandler
 
             ;; Window
-            alert confirm document java navigator prompt screen
+            window alert confirm document java navigator prompt screen
             self top
 
             ;; W3C CSS

commit c2c99814f5f965491f4e24b5a345c364b601ba2b
Author: mooz <address@hidden>
Date:   Thu Feb 17 12:40:45 2011 +0900

    Array pattern of the destructuring assignment allows empty element.

diff --git a/js2-mode.el b/js2-mode.el
index bcb3b76..a8784b4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7427,7 +7427,8 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
        decl-type face ignore-not-in-block)))
    ((js2-array-node-p node)
     (dolist (elem (js2-array-node-elems node))
-      (js2-define-destruct-symbols elem decl-type face ignore-not-in-block)))
+      (when elem
+        (js2-define-destruct-symbols elem decl-type face 
ignore-not-in-block))))
    (t (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
                         (js2-node-len node)))))
 

commit ae515432ca997c69911123c12c4c4051b30d5107
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 23:00:41 2011 +0300

    js2-define-destruct-symbols: report error position and length

diff --git a/js2-mode.el b/js2-mode.el
index f51f253..bcb3b76 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7428,7 +7428,8 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
    ((js2-array-node-p node)
     (dolist (elem (js2-array-node-elems node))
       (js2-define-destruct-symbols elem decl-type face ignore-not-in-block)))
-   (t (js2-report-error "msg.no.parm"))))
+   (t (js2-report-error "msg.no.parm" nil (js2-node-abs-pos node)
+                        (js2-node-len node)))))
 
 (defun js2-parse-function-params (fn-node pos)
   (if (js2-match-token js2-RP)

commit 1ba2939770a269dfb9a96daa3a67f4c204ffa4ef
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 22:07:20 2011 +0300

    Update credits

diff --git a/js2-mode.el b/js2-mode.el
index 27350ed..f51f253 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3,7 +3,8 @@
 ;; Copyright (C) 2009  Free Software Foundation, Inc.
 
 ;; Author:  Steve Yegge <address@hidden>
-;;          mooz        <address@hidden>
+;; Contributors:  mooz <address@hidden>
+;;                Dmitry Gutov <address@hidden>
 ;; Version:  See `js2-mode-version'
 ;; Keywords:  languages, javascript
 

commit ce605762cfd014d0379cc5766a610082abb93374
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 21:56:09 2011 +0300

    Update README

diff --git a/README.md b/README.md
index 4d7b235..04d5dd1 100644
--- a/README.md
+++ b/README.md
@@ -143,6 +143,33 @@ Examples of output:
 
 No support for library-specific extension methods like _.extend.
 
+Highlights undeclared/external variables
+----------------------------------------
+
+Original mode highlights them only on the left side of assignments:
+
+    var house;
+    hose = new House(); // highlights "hose"
+
+Here they are highlighted in all expressions:
+    
+    function feed(fishes, food) {
+        for each (var fish in fshes) { // highlights "fshes"
+            food.feed(fsh); // highlights "fsh"
+        }
+        hood.discard(); // highlights "hood"
+    }
+
+Destructuring assignments and array comprehensions (JS 1.7) are supported:
+
+    let three, [one, two] = [1, 2];
+    thee = one + two; // highlights "thee" 
+
+    function revenue(goods) {
+        // highlights "coast"
+        return [price - coast for each ({price, cost} in goods)].reduce(add);
+    }
+    
 Bugs
 ====
 

commit f68469bdf2908165a6276b3c0ea9b8286e8bbade
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 20:42:00 2011 +0300

    Declare and fontify destructured identifiers inside array comp loops

diff --git a/js2-mode.el b/js2-mode.el
index 2aeb1a3..27350ed 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7405,27 +7405,28 @@ Scanner should be initialized."
     (js2-node-add-children fn-node pn)
     pn))
 
-(defun js2-define-destruct-symbols (decl-type face node)
+(defun js2-define-destruct-symbols (node decl-type face &optional 
ignore-not-in-block)
   "Declare and fontify destructuring parameters inside NODE.
 NODE is either `js2-array-node', `js2-object-node', or `js2-name-node'."
   (cond
    ((js2-name-node-p node)
     (let (leftpos)
-      (js2-define-symbol decl-type (js2-name-node-name node) node)
+      (js2-define-symbol decl-type (js2-name-node-name node)
+                         node ignore-not-in-block)
       (js2-set-face (setq leftpos (js2-node-abs-pos node))
                     (+ leftpos (js2-node-len node))
                     face 'record)))
    ((js2-object-node-p node)
     (dolist (elem (js2-object-node-elems node))
       (js2-define-destruct-symbols
-       decl-type face
        (if (js2-object-prop-node-p elem)
            (js2-object-prop-node-right elem)
          ;; abbreviated destructuring {a, b}
-         elem))))
+         elem)
+       decl-type face ignore-not-in-block)))
    ((js2-array-node-p node)
     (dolist (elem (js2-array-node-elems node))
-      (js2-define-destruct-symbols decl-type face elem)))
+      (js2-define-destruct-symbols elem decl-type face ignore-not-in-block)))
    (t (js2-report-error "msg.no.parm"))))
 
 (defun js2-parse-function-params (fn-node pos)
@@ -7438,9 +7439,9 @@ NODE is either `js2-array-node', `js2-object-node', or 
`js2-name-node'."
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
               (setq param (js2-parse-primary-expr-lhs))
-              (js2-define-destruct-symbols js2-LP
-                                           'js2-function-param-face
-                                           param)
+              (js2-define-destruct-symbols param
+                                           js2-LP
+                                           'js2-function-param-face)
               (push param params))
              ;; simple name
              (t
@@ -8465,9 +8466,9 @@ Returns the parsed `js2-var-decl-node' expression node."
           (progn
             (if (and (null init) (not js2-in-for-init))
                 (js2-report-error "msg.destruct.assign.no.init"))
-            (js2-define-destruct-symbols decl-type
-                                         'font-lock-variable-name-face
-                                         destructuring)
+            (js2-define-destruct-symbols destructuring
+                                         decl-type
+                                         'font-lock-variable-name-face)
             (setf (js2-var-init-node-target vi) destructuring))
         (setf (js2-var-init-node-target vi) name))
       (setf (js2-var-init-node-initializer vi) init)
@@ -9481,7 +9482,9 @@ Last token peeked should be the initial FOR."
            ((or (= tt js2-LB)
                 (= tt js2-LC))
             ;; handle destructuring assignment
-            (setq iter (js2-parse-primary-expr-lhs)))
+            (setq iter (js2-parse-primary-expr-lhs))
+            (js2-define-destruct-symbols iter js2-LET
+                                         'font-lock-variable-name-face t))
            ((js2-valid-prop-name-token tt)
             (js2-consume-token)
             (setq iter (js2-create-name-node)))

commit 454b7560636b6a483cd7a3e4a4c0c293f250df29
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 19:50:59 2011 +0300

    Rearrange expr and loop scopes in array comprehension

diff --git a/js2-mode.el b/js2-mode.el
index 0034be4..2aeb1a3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9349,6 +9349,8 @@ array-literals, array comprehensions and regular 
expressions."
         elems
         pn
         (continue t))
+    (unless js2-is-in-lhs
+        (js2-push-scope (make-js2-scope))) ; for array comp
     (while continue
       (setq tt (js2-peek-token))
       (cond
@@ -9404,6 +9406,8 @@ array-literals, array comprehensions and regular 
expressions."
         (push (js2-parse-assign-expr) elems)
         (setq after-lb-or-comma nil
               after-comma nil))))
+    (unless js2-is-in-lhs
+      (js2-pop-scope))
     pn))
 
 (defun js2-parse-array-comprehension (expr pos)
@@ -9412,11 +9416,22 @@ EXPR is the first expression after the opening 
left-bracket.
 POS is the beginning of the LB token preceding EXPR.
 We should have just parsed the 'for' keyword before calling this function."
   (let (loops
+        loop
+        first
+        prev
         filter
         if-pos
         result)
     (while (= (js2-peek-token) js2-FOR)
-      (push (js2-parse-array-comp-loop) loops))
+      (let ((prev (car loops))) ; rearrange scope chain
+        (push (setq loop (js2-parse-array-comp-loop)) loops)
+        (if prev ; each loop is parent scope to the next one
+            (setf (js2-scope-parent-scope loop) prev)
+          ; first loop takes expr scope's parent
+          (setf (js2-scope-parent-scope (setq first loop))
+                (js2-scope-parent-scope js2-current-scope)))))
+    ;; set expr scope's parent to the last loop
+    (setf (js2-scope-parent-scope js2-current-scope) (car loops))
     (when (= (js2-peek-token) js2-IF)
       (js2-consume-token)
       (setq if-pos (- js2-token-beg pos)  ; relative
@@ -9432,6 +9447,7 @@ We should have just parsed the 'for' keyword before 
calling this function."
                                            :if-pos if-pos))
     (apply #'js2-node-add-children result expr (car filter)
            (js2-array-comp-node-loops result))
+    (setq js2-current-scope first) ; pop to the first loop
     result))
 
 (defun js2-parse-array-comp-loop ()

commit 85772e3fb3c79dc5fd6ce0f407a5fcb04f7d49bb
Author: Dmitry Gutov <address@hidden>
Date:   Wed Feb 16 15:18:38 2011 +0300

    Declare and fontify destructured identifiers inside function
    parameters and variable declarations.

diff --git a/js2-mode.el b/js2-mode.el
index 9d18404..0034be4 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3534,8 +3534,10 @@ You can tell the quote type by looking at the first 
character."
                                                      (pos js2-ts-cursor)
                                                      len
                                                      elems)))
-  "AST node for an object literal expression."
-  elems)  ; a lisp list of `js2-object-prop-node'
+  "AST node for an object literal expression.
+`elems' is a list of either `js2-object-prop-node' or `js2-name-node',
+the latter represents abbreviation in destructuring expressions."
+  elems)
 
 (put 'cl-struct-js2-object-node 'js2-visitor 'js2-visit-object-node)
 (put 'cl-struct-js2-object-node 'js2-printer 'js2-print-object-node)
@@ -7403,6 +7405,29 @@ Scanner should be initialized."
     (js2-node-add-children fn-node pn)
     pn))
 
+(defun js2-define-destruct-symbols (decl-type face node)
+  "Declare and fontify destructuring parameters inside NODE.
+NODE is either `js2-array-node', `js2-object-node', or `js2-name-node'."
+  (cond
+   ((js2-name-node-p node)
+    (let (leftpos)
+      (js2-define-symbol decl-type (js2-name-node-name node) node)
+      (js2-set-face (setq leftpos (js2-node-abs-pos node))
+                    (+ leftpos (js2-node-len node))
+                    face 'record)))
+   ((js2-object-node-p node)
+    (dolist (elem (js2-object-node-elems node))
+      (js2-define-destruct-symbols
+       decl-type face
+       (if (js2-object-prop-node-p elem)
+           (js2-object-prop-node-right elem)
+         ;; abbreviated destructuring {a, b}
+         elem))))
+   ((js2-array-node-p node)
+    (dolist (elem (js2-array-node-elems node))
+      (js2-define-destruct-symbols decl-type face elem)))
+   (t (js2-report-error "msg.no.parm"))))
+
 (defun js2-parse-function-params (fn-node pos)
   (if (js2-match-token js2-RP)
       (setf (js2-function-node-rp fn-node) (- js2-token-beg pos))
@@ -7412,7 +7437,11 @@ Scanner should be initialized."
             (cond
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
-              (push (js2-parse-primary-expr-lhs) params))
+              (setq param (js2-parse-primary-expr-lhs))
+              (js2-define-destruct-symbols js2-LP
+                                           'js2-function-param-face
+                                           param)
+              (push param params))
              ;; simple name
              (t
               (js2-must-match js2-NAME "msg.no.parm")
@@ -8436,6 +8465,9 @@ Returns the parsed `js2-var-decl-node' expression node."
           (progn
             (if (and (null init) (not js2-in-for-init))
                 (js2-report-error "msg.destruct.assign.no.init"))
+            (js2-define-destruct-symbols decl-type
+                                         'font-lock-variable-name-face
+                                         destructuring)
             (setf (js2-var-init-node-target vi) destructuring))
         (setf (js2-var-init-node-target vi) name))
       (setf (js2-var-init-node-initializer vi) init)
@@ -9538,7 +9570,6 @@ When `js2-is-in-lhs' is t, forms like {a, b, c} will be 
permitted."
              (or (= ctk js2-COMMA)
                  (= ctk js2-RC)
                  (js2-valid-prop-name-token ctk))))
-      (js2-set-face ppos pend 'font-lock-variable-name-face 'record)
       name)
      ;; regular prop
      (t

commit 4102c5682b633a6d5b58a4c26e5822378107766e
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 15 04:06:58 2011 +0300

    "assign to" -> "use"

diff --git a/js2-mode.el b/js2-mode.el
index 683d7f3..9d18404 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1135,8 +1135,8 @@ declarations to `js2-recorded-identifiers', which see."
   '((t :foreground "orange"))
   "Face used to highlight undeclared variable identifiers.
 An undeclared variable is any variable not declared with var or let
-in the current scope or any lexically enclosing scope.  If you assign
-to such a variable, then you are either expecting it to originate from
+in the current scope or any lexically enclosing scope.  If you use
+such a variable, then you are either expecting it to originate from
 another file, or you've got a potential bug."
   :group 'js2-mode)
 

commit 316e0759a416de2f2cbb234da54a3a0d74abc37d
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 15 03:58:56 2011 +0300

    No need for progn here

diff --git a/js2-mode.el b/js2-mode.el
index c1e10a9..683d7f3 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9522,12 +9522,11 @@ When `js2-is-in-lhs' is t, forms like {a, b, c} will be 
permitted."
            (= (js2-peek-token) js2-NAME)
            (or (string= prop "get")
                (string= prop "set")))
-      (progn
-        (js2-consume-token)
-        (js2-set-face ppos pend 'font-lock-keyword-face 'record)  ; get/set
-        (js2-record-face 'font-lock-function-name-face)      ; for peeked name
-        (setq name (js2-create-name-node)) ; discard get/set & use peeked name
-        (js2-parse-getter-setter-prop ppos name (string= prop "get"))))
+      (js2-consume-token)
+      (js2-set-face ppos pend 'font-lock-keyword-face 'record)  ; get/set
+      (js2-record-face 'font-lock-function-name-face)      ; for peeked name
+      (setq name (js2-create-name-node)) ; discard get/set & use peeked name
+      (js2-parse-getter-setter-prop ppos name (string= prop "get")))
      ;; abbreviated destructuring bind e.g., {a, b} = c;
      ;; XXX: To be honest, the value of `js2-is-in-lhs' becomes t only when
      ;; patterns are appeared in variable declaration, function parameters, 
and catch-clause.

commit 6958f53f4a1ee5133fb200fd003596341b6bf207
Author: Dmitry Gutov <address@hidden>
Date:   Tue Feb 15 03:34:40 2011 +0300

    Fix typo

diff --git a/js2-mode.el b/js2-mode.el
index 3fd4162..c1e10a9 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1141,7 +1141,7 @@ another file, or you've got a potential bug."
   :group 'js2-mode)
 
 (defcustom js2-highlight-external-variables t
-  "Non-nil to higlight undeclared variable identifiers."
+  "Non-nil to highlight undeclared variable identifiers."
   :type 'boolean
   :group 'js2-mode)
 

commit 5e9e631345fbb1a567c46f71b68bca981ff3b2d3
Author: Dmitry Gutov <address@hidden>
Date:   Mon Feb 14 23:36:18 2011 +0300

    Highlight undeclared vars everywhere, not just in assignments

diff --git a/js2-mode.el b/js2-mode.el
index 1434757..3fd4162 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -799,8 +799,8 @@ Will only be used when we finish implementing the 
interpreter.")
 
 (js2-deflocal js2-nesting-of-function 0)
 
-(js2-deflocal js2-recorded-assignments nil
-  "Tracks assignments found during parsing.")
+(js2-deflocal js2-recorded-identifiers nil
+  "Tracks identifiers found during parsing.")
 
 (defmacro js2-in-lhs (body)
   `(let ((js2-is-in-lhs t))
@@ -1127,13 +1127,13 @@ Not currently used."
 (defcustom js2-post-parse-callbacks nil
   "A list of callback functions invoked after parsing finishes.
 Currently, the main use for this function is to add synthetic
-declarations to `js2-recorded-assignments', which see."
+declarations to `js2-recorded-identifiers', which see."
   :type 'list
   :group 'js2-mode)
 
 (defface js2-external-variable-face
   '((t :foreground "orange"))
-  "Face used to highlight assignments to undeclared variables.
+  "Face used to highlight undeclared variable identifiers.
 An undeclared variable is any variable not declared with var or let
 in the current scope or any lexically enclosing scope.  If you assign
 to such a variable, then you are either expecting it to originate from
@@ -1141,7 +1141,7 @@ another file, or you've got a potential bug."
   :group 'js2-mode)
 
 (defcustom js2-highlight-external-variables t
-  "Non-nil to higlight assignments to undeclared variables."
+  "Non-nil to higlight undeclared variable identifiers."
   :type 'boolean
   :group 'js2-mode)
 
@@ -6645,25 +6645,25 @@ of a simple name.  Called before EXPR has a parent 
node."
         (js2-set-face (setq leftpos (js2-node-abs-pos name))
                       (+ leftpos (js2-node-len name))
                       'font-lock-function-name-face
-                      'record)))
-    ;; save variable assignments so we can check for undeclared later
-    ;; (can't do it here since var decls can come at end of script)
-    (when (and js2-highlight-external-variables
-               (setq name (js2-member-expr-leftmost-name left)))
-      (push (list name js2-current-scope
-                  (setq leftpos (js2-node-abs-pos name))
-                  (setq end (+ leftpos (js2-node-len name))))
-            js2-recorded-assignments))))
+                      'record)))))
+
+(defun js2-record-name-node (node)
+  "Saves NODE to `js2-recorded-identifiers' to check for undeclared variables
+later. NODE must be a name node."
+  (push (list node js2-current-scope
+              (setq leftpos (js2-node-abs-pos node))
+              (setq end (+ leftpos (js2-node-len node))))
+        js2-recorded-identifiers))
 
 (defun js2-highlight-undeclared-vars ()
-  "After entire parse is finished, look for undeclared variable assignments.
+  "After entire parse is finished, look for undeclared variable references.
 We have to wait until entire buffer is parsed, since JavaScript permits var
 decls to occur after they're used.
 
 If any undeclared var name is in `js2-externs' or `js2-additional-externs',
 it is considered declared."
   (let (name)
-    (dolist (entry js2-recorded-assignments)
+    (dolist (entry js2-recorded-identifiers)
       (destructuring-bind (name-node scope pos end) entry
         (setq name (js2-name-node-name name-node))
         (unless (or (member name js2-global-externs)
@@ -6673,7 +6673,7 @@ it is considered declared."
           (js2-set-face pos end 'js2-external-variable-face 'record)
           (js2-record-text-property pos end 'help-echo "Undeclared variable")
           (js2-record-text-property pos end 'point-entered #'js2-echo-help))))
-    (setq js2-recorded-assignments nil)))
+    (setq js2-recorded-identifiers nil)))
 
 ;;; IMenu support
 
@@ -7334,7 +7334,7 @@ Scanner should be initialized."
           js2-current-flagged-token js2-EOF
           js2-nesting-of-function 0
           js2-labeled-stmt nil
-          js2-recorded-assignments nil)  ; for js2-highlight
+          js2-recorded-identifiers nil)  ; for js2-highlight
     (while (/= (setq tt (js2-peek-token)) js2-EOF)
       (if (= tt js2-FUNCTION)
           (progn
@@ -9270,26 +9270,30 @@ array-literals, array comprehensions and regular 
expressions."
 
 (defun js2-parse-name (tt-flagged tt)
   (let ((name js2-ts-string)
-        (name-pos js2-token-beg))
-      (if (and (js2-flag-set-p tt-flagged js2-ti-check-label)
-               (= (js2-peek-token) js2-COLON))
-          (prog1
+        (name-pos js2-token-beg)
+        node)
+    (if (and (js2-flag-set-p tt-flagged js2-ti-check-label)
+             (= (js2-peek-token) js2-COLON))
+        (prog1
             ;; Do not consume colon, it is used as unwind indicator
             ;; to return to statementHelper.
             (make-js2-label-node :pos name-pos
                                  :len (- js2-token-end name-pos)
                                  :name name)
-            (js2-set-face name-pos
-                          js2-token-end
-                          'font-lock-variable-name-face 'record))
-        ;; Otherwise not a label, just a name.  Unfortunately peeking
-        ;; the next token to check for a colon has biffed js2-token-beg
-        ;; and js2-token-end.  We store the name's bounds in buffer vars
-        ;; and `js2-create-name-node' uses them.
-        (js2-save-name-token-data name-pos name)
-        (if js2-compiler-xml-available
-            (js2-parse-property-name nil name 0)
-          (js2-create-name-node 'check-activation)))))
+          (js2-set-face name-pos
+                        js2-token-end
+                        'font-lock-variable-name-face 'record))
+      ;; Otherwise not a label, just a name.  Unfortunately peeking
+      ;; the next token to check for a colon has biffed js2-token-beg
+      ;; and js2-token-end.  We store the name's bounds in buffer vars
+      ;; and `js2-create-name-node' uses them.
+      (js2-save-name-token-data name-pos name)
+      (setq node (if js2-compiler-xml-available
+                     (js2-parse-property-name nil name 0)
+                   (js2-create-name-node 'check-activation)))
+      (if js2-highlight-external-variables
+          (js2-record-name-node node))
+      node)))
 
 (defsubst js2-parse-warn-trailing-comma (msg pos elems comma-pos)
   (js2-add-strict-warning

commit e950f4a0bc51f6e79c5f1bc101949a3d3bc326bb
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 13 15:47:21 2011 +0300

    Remove an extra comma

diff --git a/README.md b/README.md
index beecc92..4d7b235 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,7 @@ Proper position for functions in nested object literals:
         bar: function() {}, // ok in original
         baz: {
              boop: function() {} // fixed here
-        },
+        }
     }
 
 Imenu support for function nesting

commit 4778b48f9148c8679c67b57e10125a4e37d12447
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 13 03:22:45 2011 +0300

    Update README

diff --git a/README.md b/README.md
index 4fb31d9..beecc92 100644
--- a/README.md
+++ b/README.md
@@ -101,7 +101,7 @@ In this js2-mode.el,
         return bar;  // fixed
 
 Fixes in Imenu support
------------------------
+----------------------
 
 Supports element-get form:
 
@@ -117,8 +117,8 @@ Proper position for functions in nested object literals:
         },
     }
 
-Imenu support for nested named functions
-----------------------------------------
+Imenu support for function nesting
+----------------------------------
 
 Supports one level of nesting:
 
@@ -141,7 +141,7 @@ Examples of output:
 * 
[Backbone.js](https://github.com/documentcloud/backbone/blob/master/backbone.js)
 -> <https://gist.github.com/824260>
 
-No support for library-specific extension methods, though, like _.extend.
+No support for library-specific extension methods like _.extend.
 
 Bugs
 ====

commit 39db69eec92d5d39c6ba0d04223dd8d18bef339d
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 13 03:11:01 2011 +0300

    Update README

diff --git a/README.md b/README.md
index 780a1e6..4fb31d9 100644
--- a/README.md
+++ b/README.md
@@ -117,6 +117,32 @@ Proper position for functions in nested object literals:
         },
     }
 
+Imenu support for nested named functions
+----------------------------------------
+
+Supports one level of nesting:
+
+    function foo() {
+        function bar() { // shown as foo.bar
+            function baz() {} // hidden
+        }
+    }
+
+Top-level function can be anonymous wrapper:
+
+    (function() {
+        var foo = function() {}; // shown as foo
+    })();
+
+Examples of output:
+
+* 
[Underscore.js](https://github.com/documentcloud/underscore/blob/master/underscore.js)
+-> <https://gist.github.com/824262>
+* 
[Backbone.js](https://github.com/documentcloud/backbone/blob/master/backbone.js)
+-> <https://gist.github.com/824260>
+
+No support for library-specific extension methods, though, like _.extend.
+
 Bugs
 ====
 

commit 1be1a83342d1e5f9f474f2f4ca76cf1caff8650a
Author: Dmitry Gutov <address@hidden>
Date:   Sun Feb 13 02:55:25 2011 +0300

    Add imenu support for function nesting
    
    * Nesting is limited to 1 level
    * Assignments to 'this' inside nested functions are discarded
    * Top-level function can be anonymous, then it doesn't contribute to qname

diff --git a/js2-mode.el b/js2-mode.el
index 39d0b65..1434757 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6894,23 +6894,30 @@ For instance, following a 'this' reference requires a 
parent function node."
     (dolist (chain chains)
       ;; examine the head of each node to get its defining scope
       (setq head (car chain))
-      (cond
-       ;; if top-level/external, keep as-is
-       ((js2-node-top-level-decl-p head)
-        (push chain result))
-       ;; check for a this-reference
-       ((eq (js2-node-type head) js2-THIS)
-        (setq fn (js2-node-parent-script-or-fn head))
-        ;; if there is no parent function, or if the parent function
-        ;; is nested, discard the head node and keep the rest of the chain.
-        (if (or (null fn) (js2-nested-function-p fn))
-            (push (cdr chain) result)
-          ;; else look up parent in function-map.  If not found, discard chain.
-          (when (setq parent-chain (and js2-imenu-function-map
-                                        (gethash fn js2-imenu-function-map)))
-            ;; else discard head node and prefix parent fn qname, which is
-            ;; the parent-chain sans tail, to this chain.
-            (push (append (butlast parent-chain) (cdr chain)) result))))))
+      ;; if top-level/external, keep as-is
+      (if (js2-node-top-level-decl-p head)
+          (push chain result)
+        (cond
+         ;; starts with this-reference
+         ((js2-this-node-p head)
+          (setq fn (js2-node-parent-script-or-fn head)
+                chain (cdr chain))) ; discard this-node
+         ;; nested named function
+         ((js2-function-node-p (setq parent (js2-node-parent head)))
+          (setq fn (js2-node-parent-script-or-fn parent)))
+         ;; variable assigned a function expression
+         (t (setq fn (js2-node-parent-script-or-fn head))))
+        (unless (or (null fn) (js2-nested-function-p fn))
+          ;; if the parent function is found, and it's not nested,
+          ;; look it up in function-map.
+          (if (setq parent-chain (and js2-imenu-function-map
+                                      (gethash fn js2-imenu-function-map)))
+              ;; prefix parent fn qname, which is the
+              ;; parent-chain sans tail, to this chain.
+              (push (append (butlast parent-chain) chain) result)
+            ;; parent function is not nested, and not in function-map
+            ;; => it's anonymous top-level wrapper, discard.
+            (push chain result)))))
     ;; finally replace each node in each chain with its name.
     (dolist (chain result)
       (setq p chain)
@@ -7334,8 +7341,7 @@ Scanner should be initialized."
             (js2-consume-token)
             (setq n (js2-parse-function (if js2-called-by-compile-function
                                             'FUNCTION_EXPRESSION
-                                          'FUNCTION_STATEMENT)))
-            (js2-record-imenu-functions n))
+                                          'FUNCTION_STATEMENT))))
         ;; not a function - parse a statement
         (setq n (js2-parse-statement)))
       ;; add function or statement to script
@@ -7525,7 +7531,7 @@ Last token scanned is the close-curly for the function 
body."
                              (js2-name-node-name name)
                              fn-node))
       (if (and name
-               (eq function-type 'FUNCTION_EXPRESSION_STATEMENT))
+               (not (eq function-type 'FUNCTION_EXPRESSION)))
           (js2-record-imenu-functions fn-node)))
     (setf (js2-node-len fn-node) (- js2-ts-cursor pos)
           (js2-function-node-member-expr fn-node) member-expr-node)  ; may be 
nil

commit bd88a5665cb419ef49a8a72ba678be097f0da293
Author: Dmitry Gutov <address@hidden>
Date:   Sat Feb 12 19:17:42 2011 +0300

    Update README

diff --git a/README.md b/README.md
index 9ff2ee0..780a1e6 100644
--- a/README.md
+++ b/README.md
@@ -100,6 +100,23 @@ In this js2-mode.el,
     else if (bar)
         return bar;  // fixed
 
+Fixes in Imenu support
+-----------------------
+
+Supports element-get form:
+
+    foo["bar"] = function() {};
+    foo[647] = function() {};
+
+Proper position for functions in nested object literals:
+
+    foo = {
+        bar: function() {}, // ok in original
+        baz: {
+             boop: function() {} // fixed here
+        },
+    }
+
 Bugs
 ====
 

commit 42045e902df52fefaa88aa546f612eee55c7656b
Author: Dmitry Gutov <address@hidden>
Date:   Sat Feb 12 18:53:46 2011 +0300

    Fix js2-compute-nested-prop-get to not recognize form foo[bar]

diff --git a/js2-mode.el b/js2-mode.el
index 8ec3a3f..39d0b65 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6816,30 +6816,27 @@ VAR, if non-nil, is the expression that NODE is being 
assigned to."
           (js2-record-object-literal node qname (js2-node-pos node)))))))))
 
 (defun js2-compute-nested-prop-get (node)
-  "If NODE is of form foo.bar.baz, return component nodes as a list.
-Otherwise returns nil.  Element-gets can be treated as property-gets
-if the index expression is a name, a string, or a positive integer."
+  "If NODE is of form foo.bar, foo['bar'], or any nested combination, return
+component nodes as a list.  Otherwise return nil.  Element-gets are treated
+as property-gets if the index expression is a string, or a positive integer."
   (let (left right head)
     (cond
      ((or (js2-name-node-p node)
           (js2-this-node-p node))
       (list node))
      ;; foo.bar.baz is parenthesized as (foo.bar).baz => right operand is a 
leaf
-     ((or (and (js2-prop-get-node-p node)
-               (setq left (js2-prop-get-node-left node)
-                     right (js2-prop-get-node-right node)))
-          (and (js2-elem-get-node-p node)
-               (setq left (js2-elem-get-node-target node)
-                     right (js2-elem-get-node-element node))))
-      (if (and (or (js2-prop-get-node-p left)     ; left == foo.bar
-                   (js2-elem-get-node-p left)     ; left == foo['bar']
-                   (js2-name-node-p left)         ; left == foo
-                   (js2-this-node-p left))        ; or left == this
-               (or (js2-name-node-p right)        ; .bar
-                   (js2-string-node-p right)      ; ['bar']
-                   (and (js2-number-node-p right) ; [10]
-                        (string-match "^[0-9]+$"
-                                      (js2-number-node-value right)))))
+     ((js2-prop-get-node-p node)        ; foo.bar
+      (setq left (js2-prop-get-node-left node)
+            right (js2-prop-get-node-right node))
+      (if (setq head (js2-compute-nested-prop-get left))
+          (nconc head (list right))))
+     ((js2-elem-get-node-p node)        ; foo['bar'] or foo[101]
+      (setq left (js2-elem-get-node-target node)
+            right (js2-elem-get-node-element node))
+      (if (or (js2-string-node-p right)      ; ['bar']
+              (and (js2-number-node-p right) ; [10]
+                   (string-match "^[0-9]+$"
+                                 (js2-number-node-value right))))
           (if (setq head (js2-compute-nested-prop-get left))
               (nconc head (list right))))))))
 

commit d197cac21bc04c13da30261c907ea9213fb5db17
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 11 23:57:40 2011 +0300

    Record proper positions for function nodes in nested object literals

diff --git a/js2-mode.el b/js2-mode.el
index 6f203e0..8ec3a3f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6810,7 +6810,10 @@ VAR, if non-nil, is the expression that NODE is being 
assigned to."
          ;; foo.bar.baz = object-literal
          ;; look for nested functions:  {a: {b: function() {...} }}
          ((js2-object-node-p node)
-          (js2-record-object-literal node qname))))))))
+          ;; Node position here is still absolute, since the parser
+          ;; passes the assignment target and value expressions
+          ;; to us before they are added as children of the assignment node.
+          (js2-record-object-literal node qname (js2-node-pos node)))))))))
 
 (defun js2-compute-nested-prop-get (node)
   "If NODE is of form foo.bar.baz, return component nodes as a list.
@@ -6840,37 +6843,35 @@ if the index expression is a name, a string, or a 
positive integer."
           (if (setq head (js2-compute-nested-prop-get left))
               (nconc head (list right))))))))
 
-(defun js2-get-node-p )
-
-(defun js2-record-object-literal (node qname)
+(defun js2-record-object-literal (node qname pos)
   "Recursively process an object literal looking for functions.
 NODE is an object literal that is the right-hand child of an assignment
 expression.  QNAME is a list of nodes representing the assignment target,
 e.g. for foo.bar.baz = {...}, QNAME is (foo-node bar-node baz-node).
+POS is the absolute position of the node.
 We do a depth-first traversal of NODE.  Any functions we find are prefixed
 with QNAME plus the property name of the function and appended to the
 variable `js2-imenu-recorder'."
-  ;; Elements are relative to parent position, which is still absolute,
-  ;; since the parser passes the assignment target and value expressions
-  ;; to us before they are added as children of the assignment node.
-  (let ((pos (js2-node-pos node))
-        left right)
+  (let (left right)
     (dolist (e (js2-object-node-elems node))  ; e is a `js2-object-prop-node'
-      (setq left (js2-infix-node-left e))
-      (cond
-       ;; foo: function() {...}
-       ((js2-function-node-p (setq right (js2-infix-node-right e)))
-        (when (js2-prop-node-name left)
-          ;; As a policy decision, we record the position of the property,
-          ;; not the position of the `function' keyword, since the property
-          ;; is effectively the name of the function.
-          (push (append qname (list left) (list (+ pos (js2-node-pos e))))
-                js2-imenu-recorder)
-          (js2-record-function-qname right qname)))
-       ;; foo: {object-literal} -- add foo to qname and recurse
-       ((js2-object-node-p right)
-        (js2-record-object-literal right
-                                   (append qname (list (js2-infix-node-left 
e)))))))))
+      (let ((left (js2-infix-node-left e))
+            ;; Element positions are relative to the parent position.
+            (pos (+ pos (js2-node-pos e))))
+        (cond
+         ;; foo: function() {...}
+         ((js2-function-node-p (setq right (js2-infix-node-right e)))
+          (when (js2-prop-node-name left)
+            ;; As a policy decision, we record the position of the property,
+            ;; not the position of the `function' keyword, since the property
+            ;; is effectively the name of the function.
+            (push (append qname (list left pos))
+                  js2-imenu-recorder)
+            (js2-record-function-qname right qname)))
+         ;; foo: {object-literal} -- add foo to qname, offset position, and 
recurse
+         ((js2-object-node-p right)
+          (js2-record-object-literal right
+                                     (append qname (list (js2-infix-node-left 
e)))
+                                     (+ pos (js2-node-pos right)))))))))
 
 (defsubst js2-node-top-level-decl-p (node)
   "Return t if NODE's name is defined in the top-level scope.

commit dabef35f1a0b6718c1a717ed31d6663bca76268b
Author: Dmitry Gutov <address@hidden>
Date:   Fri Feb 11 22:30:06 2011 +0300

    Recognize form foo['a'] = function() in imenu

diff --git a/js2-mode.el b/js2-mode.el
index b9a1d15..6f203e0 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -6822,12 +6822,16 @@ if the index expression is a name, a string, or a 
positive integer."
           (js2-this-node-p node))
       (list node))
      ;; foo.bar.baz is parenthesized as (foo.bar).baz => right operand is a 
leaf
-     ((js2-prop-get-node-p node)  ; includes elem-get nodes
-      (setq left (js2-prop-get-node-left node)
-            right (js2-prop-get-node-right node))
+     ((or (and (js2-prop-get-node-p node)
+               (setq left (js2-prop-get-node-left node)
+                     right (js2-prop-get-node-right node)))
+          (and (js2-elem-get-node-p node)
+               (setq left (js2-elem-get-node-target node)
+                     right (js2-elem-get-node-element node))))
       (if (and (or (js2-prop-get-node-p left)     ; left == foo.bar
-                   (js2-name-node-p left)
-                   (js2-this-node-p left))        ; or left == foo
+                   (js2-elem-get-node-p left)     ; left == foo['bar']
+                   (js2-name-node-p left)         ; left == foo
+                   (js2-this-node-p left))        ; or left == this
                (or (js2-name-node-p right)        ; .bar
                    (js2-string-node-p right)      ; ['bar']
                    (and (js2-number-node-p right) ; [10]
@@ -6836,6 +6840,8 @@ if the index expression is a name, a string, or a 
positive integer."
           (if (setq head (js2-compute-nested-prop-get left))
               (nconc head (list right))))))))
 
+(defun js2-get-node-p )
+
 (defun js2-record-object-literal (node qname)
   "Recursively process an object literal looking for functions.
 NODE is an object literal that is the right-hand child of an assignment

commit 35db46a5c28c0160e3c681b98ef7033e48da85b8
Merge: 660deb6 cc9b329
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jan 21 08:29:16 2011 +0100

    Merge tags.


commit cc9b329bf08a525010a13de730b9fca09aad4c85
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jan 21 08:28:26 2011 +0100

    Added tag V-2.2 for changeset 1e7928600727

commit d77e9efb89c9d721770f6edd87cbc9166ff10a79
Merge: 660deb6 3ad7a03
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jan 21 08:26:57 2011 +0100

    Merge branchs.


commit 660deb62e82e1e2e425054ac67835aa63f4773f8
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jan 16 08:55:20 2011 +0100

    (ioccur-fontify-buffer-p): New variable that allow to inhibit fontification 
of buffer at start of ioccur.

diff --git a/ioccur.el b/ioccur.el
index c339bfa..34c641a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -138,6 +138,13 @@ Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'boolean)
 
+(defcustom ioccur-fontify-buffer-p t
+  "*Fontify `ioccur-current-buffer' when non--nil.
+This allow to have syntactic coloration in `ioccur-buffer' but
+it slow down the start of ioccur at first time on large buffers."
+  :group 'ioccur
+  :type 'boolean)
+
 (defvar ioccur-read-char-or-event-skip-read-key nil
   "*Force not using `read-key' even if bounded.
 You should not have to set this yourself.
@@ -911,8 +918,9 @@ for commands provided in the `ioccur-buffer'."
   (setq ioccur-exit-and-quit-p nil)
   (setq ioccur-success nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
-  (message "Fontifying buffer...Please wait it could be long.")
-  (jit-lock-fontify-now) (message nil)
+  (when ioccur-fontify-buffer-p
+    (message "Fontifying buffer...Please wait it could be long.")
+    (jit-lock-fontify-now) (message nil))
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
   (setq ioccur-last-window-configuration (current-window-configuration))
   (if (and (not initial-input)

commit 22c95e4ed0106625fdc357b454c4b8ea111b58b9
Author: mooz <address@hidden>
Date:   Sun Jan 2 14:51:24 2011 +0900

    reparse only `js2-use-ast-for-indentation-p` is non-nil

diff --git a/js2-mode.el b/js2-mode.el
index e3a6ee5..b9a1d15 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -232,6 +232,11 @@ regardless of the beginning bracket position."
   :group 'js2-mode
   :type 'boolean)
 
+(defcustom js2-use-ast-for-indentation-p nil
+  "Non-nil to use AST for indentation and make it more robust."
+  :group 'js2-mode
+  :type 'boolean)
+
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.
 This is unusual for Emacs modes but common in IDEs like Eclipse."
@@ -9895,7 +9900,9 @@ In particular, return the buffer position of the first 
`for' kwd."
     (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
           (continued-expr-p (js-continued-expression-p))
-          (multiline-declaration-offset (js-get-multiline-declaration-offset))
+          (multiline-declaration-offset (or (and js2-use-ast-for-indentation-p
+                                                 
(js-get-multiline-declaration-offset))
+                                            0))
           (bracket (nth 1 parse-status))
           beg)
       (cond
@@ -10214,8 +10221,8 @@ If so, we don't ever want to use bounce-indent."
 (defun js2-indent-line ()
   "Indent the current line as JavaScript source text."
   (interactive)
-  ;; TODO: do not reparse
-  (js2-reparse)
+  (when js2-use-ast-for-indentation-p
+    (js2-reparse))
   (let (parse-status
         current-indent
         offset

commit 84978588c7d21b3699cc8d22ceb080f0d650520f
Author: mooz <address@hidden>
Date:   Sun Jan 2 14:16:34 2011 +0900

    reparse line in indentation

diff --git a/js2-mode.el b/js2-mode.el
index 1c06b0e..e3a6ee5 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10214,6 +10214,8 @@ If so, we don't ever want to use bounce-indent."
 (defun js2-indent-line ()
   "Indent the current line as JavaScript source text."
   (interactive)
+  ;; TODO: do not reparse
+  (js2-reparse)
   (let (parse-status
         current-indent
         offset

commit 2a560d880071eaf58a4bf299105ebb817da3fc90
Merge: dc30c57 a301f3f
Author: mooz <address@hidden>
Date:   Thu Dec 30 18:39:19 2010 +0900

    Merge branch 'master' of github.com:mooz/js2-mode


commit dc30c57729a95d3d63fa45fa3ddad6275feb3dd3
Author: mooz <address@hidden>
Date:   Thu Dec 30 11:17:37 2010 +0900

    fixed bugs indentation

diff --git a/js2-mode.el b/js2-mode.el
index 9ebca58..1c06b0e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9811,8 +9811,8 @@ indented to the same column as the current line."
 
 "
   (let* ((node (js2-node-at-point))
-         (pnode (js2-node-parent node))
-         (pnode-type (js2-node-type pnode)))
+         (pnode (and node (js2-node-parent node)))
+         (pnode-type (and pnode (js2-node-type pnode))))
     (if (and node
              (= js2-NAME (js2-node-type node))
              (or

commit a301f3fe738ab729d9a0188e9a82c2fbe409dc96
Author: mooz <address@hidden>
Date:   Thu Dec 30 11:17:37 2010 +0900

    fixed bugs indentation

diff --git a/js2-mode.el b/js2-mode.el
index 9ebca58..1c06b0e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9811,8 +9811,8 @@ indented to the same column as the current line."
 
 "
   (let* ((node (js2-node-at-point))
-         (pnode (js2-node-parent node))
-         (pnode-type (js2-node-type pnode)))
+         (pnode (and node (js2-node-parent node)))
+         (pnode-type (and pnode (js2-node-type pnode))))
     (if (and node
              (= js2-NAME (js2-node-type node))
              (or

commit 4b37646e41b1b0200a34511c93e05f354cdbff54
Author: mooz <address@hidden>
Date:   Wed Dec 29 14:45:17 2010 +0900

    oops

diff --git a/js2-mode.el b/js2-mode.el
index 2bae841..9ebca58 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9927,6 +9927,8 @@ In particular, return the buffer position of the first 
`for' kwd."
                    (current-column))
                   (continued-expr-p
                    (+ (current-column) (* 2 js2-basic-offset)))
+                  ((> multiline-declaration-offset 0)
+                   (+ (current-column) js2-basic-offset 
multiline-declaration-offset))
                   (t
                    (+ (current-column) js2-basic-offset)))))
          (t

commit 4804cff20260e0fe5bf39b1659522be88719fa8a
Author: mooz <address@hidden>
Date:   Wed Dec 29 13:56:03 2010 +0900

    use offset 4 for `var` and `let`, and 6 for `const`.

diff --git a/js2-mode.el b/js2-mode.el
index b35d24d..2bae841 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9767,17 +9767,6 @@ a comma)."
   (save-excursion
     (back-to-indentation)
     (or (js-looking-at-operator-p)
-        ;; var a = 10,
-        ;;     b = 20; <- this
-        (let* ((node (js2-node-at-point))
-               (pnode (js2-node-parent node))
-               (pnode-type (js2-node-type pnode)))
-          (and node
-               (= js2-NAME (js2-node-type node))
-               (or
-                (= js2-VAR pnode-type)
-                (= js2-LET pnode-type)
-                (= js2-CONST pnode-type))))
         ;; comment
         (and (js-re-search-backward "\n" nil t)
             (progn
@@ -9811,6 +9800,30 @@ indented to the same column as the current line."
                           "\\<while\\>" (point-at-eol) t))
                     (= (current-indentation) saved-indent)))))))))
 
+(defun js-get-multiline-declaration-offset ()
+  "Returns offset (> 0) if the current line is part of
+ multi-line variable declaration like below example, and
+ returns 0 otherwise.
+
+ var a = 10,
+     b = 20,
+     c = 30;
+
+"
+  (let* ((node (js2-node-at-point))
+         (pnode (js2-node-parent node))
+         (pnode-type (js2-node-type pnode)))
+    (if (and node
+             (= js2-NAME (js2-node-type node))
+             (or
+              (= js2-VAR pnode-type)
+              (= js2-LET pnode-type)
+              (= js2-CONST pnode-type)))
+        (if (= js2-CONST pnode-type)
+            6
+          4)
+      0)))
+
 (defun js-ctrl-statement-indentation ()
   "Returns the proper indentation of the current line if it
 starts the body of a control statement without braces, else
@@ -9882,6 +9895,7 @@ In particular, return the buffer position of the first 
`for' kwd."
     (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
           (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
           (continued-expr-p (js-continued-expression-p))
+          (multiline-declaration-offset (js-get-multiline-declaration-offset))
           (bracket (nth 1 parse-status))
           beg)
       (cond
@@ -9922,6 +9936,10 @@ In particular, return the buffer position of the first 
`for' kwd."
           (current-column))))
 
        (continued-expr-p js2-basic-offset)
+
+       ((> multiline-declaration-offset 0)
+        (+ multiline-declaration-offset))
+
        (t 0)))))
 
 (defun js2-lineup-comment (parse-status)

commit 1ecb278a72c158eda363c61e650a7b12e8a9b653
Author: mooz <address@hidden>
Date:   Wed Dec 29 00:06:07 2010 +0900

    updated README.md

diff --git a/README.md b/README.md
index 19cd7e1..9ff2ee0 100644
--- a/README.md
+++ b/README.md
@@ -22,23 +22,6 @@ See 
<http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for detail
 Differences between original js2-mode.el
 ========================================
 
-Support for abbreviated destructuring assignments
--------------------------------------------------
-
-    let {a, b}       = {a: 10, b: 20}; // Abbreviated   (Not supported in 
original js2-mode.el)
-    let {a: a, b: b} = {a: 10, b: 20}; // Same as above (Supported in original 
js2-mode.el)
-
-    (function ({responseText}) { /* */ })(xhr); // As the argument of function
-
-Support for expression closure in property value
-------------------------------------------------
-
-    let worker = {
-        get age() 20,
-        get sex() "male",
-        fire: function () _fire()
-    };
-
 Supported more popular indentation style
 ----------------------------------------
 
@@ -65,7 +48,42 @@ When js2-consistent-level-indent-inner-bracket-p is nil
                        return validate(v);
                    });
 
-Fixed the odd indentation of "else if" with no braces
+Fixed ugly indentation with multi-line variable declaration
+-----------------------------------------------------------
+
+In original js2-mode.el,
+
+    var foo = 10,
+    bar = 20,
+    baz = 30;
+
+In this js2-mode.el,
+
+    var foo = 10,
+        bar = 20,
+        baz = 30;
+
+Support for abbreviated destructuring assignments
+-------------------------------------------------
+
+    let {a, b}       = {a: 10, b: 20}; // Abbreviated   (Not supported in 
original js2-mode.el)
+    let {a: a, b: b} = {a: 10, b: 20}; // Same as above (Supported in original 
js2-mode.el)
+
+    (function ({responseText}) { /* */ })(xhr); // As the argument of function
+
+    for (let [k, { name, age }] in Iterator(obj)) // nested
+        print(k, name, age);
+
+Support for expression closure in property value
+------------------------------------------------
+
+    let worker = {
+        get age() 20,
+        get sex() "male",
+        fire: function () _fire()
+    };
+
+Fixed odd indentation of "else if" with no braces
 -----------------------------------------------------
 
 In original js2-mode.el,

commit e62f418b1b7147ca9034cf6d7b1eec1e7f3ed45d
Author: mooz <address@hidden>
Date:   Tue Dec 28 23:35:50 2010 +0900

    forgot `const{

diff --git a/js2-mode.el b/js2-mode.el
index 142b91d..b35d24d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9770,12 +9770,14 @@ a comma)."
         ;; var a = 10,
         ;;     b = 20; <- this
         (let* ((node (js2-node-at-point))
-               (pnode (js2-node-parent node)))
+               (pnode (js2-node-parent node))
+               (pnode-type (js2-node-type pnode)))
           (and node
                (= js2-NAME (js2-node-type node))
                (or
-                (= js2-VAR (js2-node-type pnode))
-                (= js2-LET (js2-node-type pnode)))))
+                (= js2-VAR pnode-type)
+                (= js2-LET pnode-type)
+                (= js2-CONST pnode-type))))
         ;; comment
         (and (js-re-search-backward "\n" nil t)
             (progn

commit 9eb632cf7973e5d22a5c4d1643935190658d888d
Author: mooz <address@hidden>
Date:   Tue Dec 28 23:25:02 2010 +0900

    fixed ugly indentation with multiple variable declaration. closes #1.

diff --git a/js2-mode.el b/js2-mode.el
index 6b0bcab..142b91d 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -450,7 +450,7 @@ which doesn't seem particularly useful, but Rhino permits 
it."
   :type 'boolean
   :group 'js2-mode)
 
-(defvar js2-mode-version 20100402
+(defvar js2-mode-version 20101228
   "Release number for `js2-mode'.")
 
 ;; scanner variables
@@ -9767,6 +9767,16 @@ a comma)."
   (save-excursion
     (back-to-indentation)
     (or (js-looking-at-operator-p)
+        ;; var a = 10,
+        ;;     b = 20; <- this
+        (let* ((node (js2-node-at-point))
+               (pnode (js2-node-parent node)))
+          (and node
+               (= js2-NAME (js2-node-type node))
+               (or
+                (= js2-VAR (js2-node-type pnode))
+                (= js2-LET (js2-node-type pnode)))))
+        ;; comment
         (and (js-re-search-backward "\n" nil t)
             (progn
               (skip-chars-backward " \t")

commit e3c8aff2664511308b8bf47206bc650b7dfef590
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 22 12:38:12 2010 +0100

    (ioccur-goto-line) Forget to put back docstring.

diff --git a/ioccur.el b/ioccur.el
index 015e560..c339bfa 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -482,6 +482,7 @@ See `ioccur-find-buffer-matching1'."
     (goto-char pos)))
 
 (defun ioccur-goto-line (lineno)
+  "Goto LINENO without modifying outline visibility if needed."
   (flet ((gotoline (numline)
            (goto-char (point-min)) (forward-line (1- numline))))
     (if (or (eq major-mode 'org-mode)

commit 75aecddbcccc9baa80b83838936c07ba192b962c
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 22 12:29:26 2010 +0100

    (ioccur-goto-line) Fix typo.

diff --git a/ioccur.el b/ioccur.el
index 672be95..015e560 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -489,7 +489,7 @@ See `ioccur-find-buffer-matching1'."
         (progn
           (gotoline lineno)
           (org-reveal))
-        (goto-line lineno))))
+        (gotoline lineno))))
 
 (defun ioccur-forward-line (n)
   "Forward N lines but empty one's."

commit 237a5de8e9414a300950a2dc4f3a21541ec1818f
Merge: 3ad7a03 353a253
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 22 12:31:15 2010 +0100

    Merge branchs.


commit 353a253053057cf04c6a26ab81d3392bc49fefd0
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 22 12:26:38 2010 +0100

    (ioccur-goto-line) Simplify, use org-reveal.

diff --git a/ioccur.el b/ioccur.el
index 868e048..672be95 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -481,29 +481,15 @@ See `ioccur-find-buffer-matching1'."
     (pop-to-buffer ioccur-current-buffer)
     (goto-char pos)))
 
-
 (defun ioccur-goto-line (lineno)
-  "Goto LINENO without modifying outline visibility if needed."
   (flet ((gotoline (numline)
            (goto-char (point-min)) (forward-line (1- numline))))
-    (if (and (fboundp 'org-save-outline-visibility)
-             (or (eq major-mode 'org-mode)
-                 outline-minor-mode))
+    (if (or (eq major-mode 'org-mode)
+            outline-minor-mode)
         (progn
-          ;; Open all, goto line LINENO, move to
-          ;; precedent heading and restore precedent state
-          ;; of visibility.
-          (org-save-outline-visibility nil
-            (show-all)
-            (gotoline lineno)
-            (outline-previous-heading))
-          ;; Make heading visible
-          (outline-show-heading)
-          ;; Open heading
-          (show-subtree)
-          (gotoline lineno))
-        (show-all)
-        (gotoline lineno))))
+          (gotoline lineno)
+          (org-reveal))
+        (goto-line lineno))))
 
 (defun ioccur-forward-line (n)
   "Forward N lines but empty one's."

commit 3ad7a03987c6a8ad1e967f60a4f220c5fcf0842c
Merge: 4db4074 0f3365f
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Dec 16 10:34:05 2010 +0100

    Merge branchs.


commit 0f3365f747b624641a00250d22b5a9046b9a8fd2
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Dec 16 08:29:03 2010 +0100

    (ioccur-jump): Use match-beginning instead of searching backward.

diff --git a/ioccur.el b/ioccur.el
index 42fa9da..868e048 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -561,7 +561,7 @@ Move point to first occurence of `ioccur-pattern'."
       ;; of what match `ioccur-pattern'.
       (when (funcall ioccur-search-function
                      ioccur-pattern (point-at-eol) t)
-        (funcall back-search-fn ioccur-pattern (point-at-bol) t))
+        (goto-char (match-beginning 0)))
       (ioccur-color-matched-line))))
 
 ;;;###autoload

commit 14e67f54390d0ac544ac5358acc2ccc199ae4aa6
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 15 09:36:53 2010 +0100

    (ioccur-goto-line) Check if org-save-outline-visibility id bound.

diff --git a/ioccur.el b/ioccur.el
index 1e8e333..42fa9da 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -481,12 +481,14 @@ See `ioccur-find-buffer-matching1'."
     (pop-to-buffer ioccur-current-buffer)
     (goto-char pos)))
 
+
 (defun ioccur-goto-line (lineno)
   "Goto LINENO without modifying outline visibility if needed."
   (flet ((gotoline (numline)
            (goto-char (point-min)) (forward-line (1- numline))))
-    (if (or (eq major-mode 'org-mode)
-            outline-minor-mode)
+    (if (and (fboundp 'org-save-outline-visibility)
+             (or (eq major-mode 'org-mode)
+                 outline-minor-mode))
         (progn
           ;; Open all, goto line LINENO, move to
           ;; precedent heading and restore precedent state
@@ -500,6 +502,7 @@ See `ioccur-find-buffer-matching1'."
           ;; Open heading
           (show-subtree)
           (gotoline lineno))
+        (show-all)
         (gotoline lineno))))
 
 (defun ioccur-forward-line (n)

commit 0fc7fce20043125765cfcf4100e5017a56f410f5
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Dec 15 08:29:43 2010 +0100

    (ioccur-goto-line) Goto line without modifying state of outline when buffer 
is outline based.
    
    (ioccur-jump) Don't show-all use only new ioccur-goto-line.

diff --git a/ioccur.el b/ioccur.el
index f8cf113..1e8e333 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -481,10 +481,26 @@ See `ioccur-find-buffer-matching1'."
     (pop-to-buffer ioccur-current-buffer)
     (goto-char pos)))
 
-(defun ioccur-goto-line (numline)
-  "Non--interactive version of `goto-line'.
-Goto NUMLINE."
-  (goto-char (point-min)) (forward-line (1- numline)))
+(defun ioccur-goto-line (lineno)
+  "Goto LINENO without modifying outline visibility if needed."
+  (flet ((gotoline (numline)
+           (goto-char (point-min)) (forward-line (1- numline))))
+    (if (or (eq major-mode 'org-mode)
+            outline-minor-mode)
+        (progn
+          ;; Open all, goto line LINENO, move to
+          ;; precedent heading and restore precedent state
+          ;; of visibility.
+          (org-save-outline-visibility nil
+            (show-all)
+            (gotoline lineno)
+            (outline-previous-heading))
+          ;; Make heading visible
+          (outline-show-heading)
+          ;; Open heading
+          (show-subtree)
+          (gotoline lineno))
+        (gotoline lineno))))
 
 (defun ioccur-forward-line (n)
   "Forward N lines but empty one's."
@@ -537,7 +553,6 @@ Move point to first occurence of `ioccur-pattern'."
       (if win-conf
           (set-window-configuration win-conf)
           (pop-to-buffer ioccur-current-buffer))
-      (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos) (recenter)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-pattern'.

commit b874bf4e5ad31c06dc328f828c4126dc2d674a1d
Author: Chris Wanstrath <address@hidden>
Date:   Tue Dec 14 00:17:17 2010 -0800

    --no-wrap is deprecated; please use --bare instead.

diff --git a/coffee-mode.el b/coffee-mode.el
index eb69449..bbd6fe6 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -181,7 +181,7 @@ path."
   (call-process-region start end coffee-command nil
                        (get-buffer-create coffee-compiled-buffer-name)
                        nil
-                       "-s" "-p" "--no-wrap")
+                       "-s" "-p" "--bare")
   (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
   (funcall coffee-js-mode)
   (goto-char (point-min)))

commit 36b220d28f195cd650063a52bd0a78e0351649f9
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Dec 12 12:53:50 2010 +0100

    (ioccur-highlight-match-on-line): Bugfix: Don't higlight line numbers when 
matching all beginning of line.

diff --git a/ioccur.el b/ioccur.el
index a142796..f8cf113 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -329,7 +329,7 @@ Special commands:
 (defun ioccur-highlight-match-on-line (regexp)
   "Highlight all occurences of REGEXP on precedent line."
   (save-excursion
-    (forward-line -1)
+    (forward-line -1) (re-search-forward "\\(\\s-[0-9]+:\\)" nil t)
     (while (and (funcall ioccur-search-function regexp (point-at-eol) t)
                 ;; If length of match is null exit loop.
                 ;; e.g when searching "^".

commit 05a0fb7edcde344216b104edd8b91e80b15fc3a4
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Dec 9 09:06:13 2010 +0100

    Change compatibility to 22.3

diff --git a/ioccur.el b/ioccur.el
index e01644e..a142796 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -4,7 +4,7 @@
 
 ;; Copyright (C) 2010 Thierry Volpiatto, all rights reserved.
 
-;; Compatibility: GNU Emacs 23.1+
+;; Compatibility: GNU Emacs >=22.3
 
 ;; X-URL: http://mercurial.intuxication.org/hg/ioccur
 

commit cdd3c94f88d9bee4fb730817992def8106396ee6
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Dec 6 17:30:21 2010 +0100

    (window-system): New, add compatibility with older Emacs, Thanks Elena ;-).

diff --git a/ioccur.el b/ioccur.el
index 59a4a81..e01644e 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -231,6 +231,11 @@ Special commands:
   (loop for i in seq for index from 0
      when (funcall test i item) return index))
 
+;; Compatibility
+(unless (fboundp 'window-system)
+  (defun window-system (&optional arg)
+    window-system))
+
 ;;; Iterators.
 (defmacro ioccur-iter-list (list-obj)
   "Return an iterator from list LIST-OBJ."

commit 7e07083ed47e3476e2c67b5574e50c41bd5b64a0
Author: mooz <address@hidden>
Date:   Fri Dec 3 01:02:23 2010 +0900

    ouch

diff --git a/js2-mode.el b/js2-mode.el
index 735c6a7..6b0bcab 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9176,7 +9176,7 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
       (js2-node-add-children pn namespace expr))))
 
 (defsubst js2-parse-primary-expr-lhs ()
-  (let ((js2-in-lhs t))
+  (let ((js2-is-in-lhs t))
     (js2-parse-primary-expr)))
 
 (defun js2-parse-primary-expr ()

commit 42276059947706958938756fd56106fea9cc7bc0
Author: mooz <address@hidden>
Date:   Thu Dec 2 23:33:20 2010 +0900

    oops

diff --git a/js2-mode.el b/js2-mode.el
index b879a26..735c6a7 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -8393,7 +8393,7 @@ Returns the parsed `js2-var-decl-node' expression node."
             init nil)
       (if (or (= tt js2-LB) (= tt js2-LC))
           ;; Destructuring assignment, e.g., var [a, b] = ...
-          (setq destructuring (js2-parse-primary-expr t)
+          (setq destructuring (js2-parse-primary-expr-lhs)
                 end (js2-node-end destructuring))
         ;; Simple variable name
         (when (js2-must-match js2-NAME "msg.bad.var")

commit 2ef2b38f4dbb3e4012efcfc48fb8eb81aa189704
Author: mooz <address@hidden>
Date:   Thu Dec 2 23:31:34 2010 +0900

    support patterns like [{a}]

diff --git a/js2-mode.el b/js2-mode.el
index 612ebd0..b879a26 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -797,6 +797,17 @@ Will only be used when we finish implementing the 
interpreter.")
 (js2-deflocal js2-recorded-assignments nil
   "Tracks assignments found during parsing.")
 
+(defmacro js2-in-lhs (body)
+  `(let ((js2-is-in-lhs t))
+     ,body))
+
+(defmacro js2-in-rhs (body)
+  `(let ((js2-is-in-lhs nil))
+     ,body))
+
+(js2-deflocal js2-is-in-lhs nil
+  "True while parsing lhs statement")
+
 (defcustom js2-global-externs nil
   "A list of any extern names you'd like to consider always declared.
 This list is global and is used by all js2-mode files.
@@ -7386,7 +7397,7 @@ Scanner should be initialized."
             (cond
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
-              (push (js2-parse-primary-expr t) params))
+              (push (js2-parse-primary-expr-lhs) params))
              ;; simple name
              (t
               (js2-must-match js2-NAME "msg.no.parm")
@@ -8541,6 +8552,7 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
             tt (js2-peek-token))
       (when (and (<= js2-first-assign tt)
                  (<= tt js2-last-assign))
+        ;; tt express assignment (=, |=, ^=, ..., %=)
         (js2-consume-token)
         (setq op-pos (- js2-token-beg pos)  ; relative
               left pn
@@ -9163,13 +9175,14 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
                                           :rb (js2-relpos rb pos)))
       (js2-node-add-children pn namespace expr))))
 
-(defun js2-parse-primary-expr (&optional lhs)
+(defsubst js2-parse-primary-expr-lhs ()
+  (let ((js2-in-lhs t))
+    (js2-parse-primary-expr)))
+
+(defun js2-parse-primary-expr ()
   "Parses a literal (leaf) expression of some sort.
 Includes complex literals such as functions, object-literals,
-array-literals, array comprehensions and regular expressions.
-When `lhs' is t, we assume the given primary expression appeared in the left 
hand side
-and treat it in the somewhat special way.
-ex) {a, b} is permitted only when the `lhs' is t."
+array-literals, array comprehensions and regular expressions."
   (let ((tt-flagged (js2-next-flagged-token))
         pn      ; parent node  (usually return value)
         tt
@@ -9184,7 +9197,7 @@ ex) {a, b} is permitted only when the `lhs' is t."
      ((= tt js2-LB)
       (js2-parse-array-literal))
      ((= tt js2-LC)
-      (js2-parse-object-literal lhs))
+      (js2-parse-object-literal))
      ((= tt js2-LET)
       (js2-parse-let js2-token-beg))
      ((= tt js2-LP)
@@ -9310,6 +9323,20 @@ ex) {a, b} is permitted only when the `lhs' is t."
         (when after-comma
           (js2-parse-warn-trailing-comma "msg.array.trailing.comma"
                                          pos elems after-comma)))
+       ;; destructuring binding
+       (js2-is-in-lhs
+        (push (if (or (= tt js2-LC)
+                      (= tt js2-LB)
+                      (= tt js2-NAME))
+                  ;; [a, b, c] | {a, b, c} | {a:x, b:y, c:z} | a
+                  (js2-parse-primary-expr-lhs)
+                ;; invalid pattern
+                (js2-consume-token)
+                (js2-report-error "msg.bad.var")
+                (make-js2-error-node))
+              elems)
+        (setq after-lb-or-comma nil
+              after-comma nil))
        ;; array comp
        ((and (>= js2-language-version 170)
              (= tt js2-FOR)          ; check for array comprehension
@@ -9318,6 +9345,7 @@ ex) {a, b} is permitted only when the `lhs' is t."
              (not (cdr elems)))      ; but no 2nd element
         (setf continue nil
               pn (js2-parse-array-comprehension (car elems) pos)))
+
        ;; another element
        (t
         (unless after-lb-or-comma
@@ -9386,7 +9414,7 @@ Last token peeked should be the initial FOR."
            ((or (= tt js2-LB)
                 (= tt js2-LC))
             ;; handle destructuring assignment
-            (setq iter (js2-parse-primary-expr t)))
+            (setq iter (js2-parse-primary-expr-lhs)))
            ((js2-valid-prop-name-token tt)
             (js2-consume-token)
             (setq iter (js2-create-name-node)))
@@ -9414,7 +9442,7 @@ Last token peeked should be the initial FOR."
       (js2-pop-scope))
     pn))
 
-(defun js2-parse-object-literal (&optional lhs)
+(defun js2-parse-object-literal ()
   (let ((pos js2-token-beg)
         tt
         elems
@@ -9428,7 +9456,7 @@ Last token peeked should be the initial FOR."
        ((or (js2-valid-prop-name-token tt)
             (= tt js2-STRING))
         (setq after-comma nil
-              result (js2-parse-named-prop tt lhs))
+              result (js2-parse-named-prop tt))
         (if (and (null result)
                  (not js2-recover-from-parse-errors))
             (setq continue nil)
@@ -9458,9 +9486,9 @@ Last token peeked should be the initial FOR."
     (apply #'js2-node-add-children result (js2-object-node-elems result))
     result))
 
-(defun js2-parse-named-prop (tt &optional lhs)
+(defun js2-parse-named-prop (tt)
   "Parse a name, string, or getter/setter object property.
-When `lhs' is t, forms like {a, b, c} will be permitted."
+When `js2-is-in-lhs' is t, forms like {a, b, c} will be permitted."
   (js2-consume-token)
   (let ((string-prop (and (= tt js2-STRING)
                           (make-js2-string-node)))
@@ -9482,7 +9510,11 @@ When `lhs' is t, forms like {a, b, c} will be permitted."
         (setq name (js2-create-name-node)) ; discard get/set & use peeked name
         (js2-parse-getter-setter-prop ppos name (string= prop "get"))))
      ;; abbreviated destructuring bind e.g., {a, b} = c;
-     ((and lhs
+     ;; XXX: To be honest, the value of `js2-is-in-lhs' becomes t only when
+     ;; patterns are appeared in variable declaration, function parameters, 
and catch-clause.
+     ;; We have to set t to `js2-is-in-lhs' when the current expressions are 
part of any
+     ;; assignment but it's difficult because it requires looking ahead of 
expression.
+     ((and js2-is-in-lhs
            (= tt js2-NAME)
            (let ((ctk (js2-peek-token)))
              (or (= ctk js2-COMMA)

commit f9cf2429b1fe0a38bd806c95de359141ab7ec61c
Author: mooz <address@hidden>
Date:   Wed Dec 1 12:10:04 2010 +0900

    Allow abbreviated destructuring assignment in array comprehension

diff --git a/js2-mode.el b/js2-mode.el
index 80a5f28..612ebd0 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9386,7 +9386,7 @@ Last token peeked should be the initial FOR."
            ((or (= tt js2-LB)
                 (= tt js2-LC))
             ;; handle destructuring assignment
-            (setq iter (js2-parse-primary-expr)))
+            (setq iter (js2-parse-primary-expr t)))
            ((js2-valid-prop-name-token tt)
             (js2-consume-token)
             (setq iter (js2-create-name-node)))

commit 40d9be8f0fad65f652c81df5ca68b2c983fd5c5d
Merge: 3b3c1c8 4db4074
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 12:08:15 2010 +0200

    Merge tags


commit 4db4074fed6147c2f26c6f08cb38d7ba4523ac30
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 12:07:11 2010 +0200

    Added tag V-2.1 for changeset a0a456831658

commit cc5ddfee8b7694743e5404b4e4475e11203ed693
Merge: 7f178bf 3b3c1c8
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 12:05:52 2010 +0200

    Merge branchs.


commit 3b3c1c8b67edc16ac766a7bda8f865cffddca520
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 12:01:42 2010 +0200

    No code change just reindent.

diff --git a/ioccur.el b/ioccur.el
index 97d01c8..59a4a81 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -555,7 +555,7 @@ Move point to first occurence of `ioccur-pattern'."
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
   (and (ioccur-jump ioccur-last-window-configuration)
-         (switch-to-buffer-other-window ioccur-buffer t)))
+       (switch-to-buffer-other-window ioccur-buffer t)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()

commit ee3e3559d03a59087cd2122d7e702c8c81a9d37d
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 11:33:49 2010 +0200

    (ioccur-jump-without-quit, ioccur-scroll) Don't record buffer.
    
    (ioccur) Use switch-to-buffer-other-window.

diff --git a/ioccur.el b/ioccur.el
index 070863a..97d01c8 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -555,7 +555,7 @@ Move point to first occurence of `ioccur-pattern'."
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
   (and (ioccur-jump ioccur-last-window-configuration)
-       (switch-to-buffer-other-window ioccur-buffer)))
+         (switch-to-buffer-other-window ioccur-buffer t)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()
@@ -576,7 +576,7 @@ Move point to first occurence of `ioccur-pattern'."
   (ioccur-forward-line n)
   (ioccur-color-current-line)
   (and (ioccur-jump ioccur-last-window-configuration)
-       (switch-to-buffer-other-window ioccur-buffer)))
+       (switch-to-buffer-other-window ioccur-buffer t)))
 
 ;;;###autoload
 (defun ioccur-scroll-down ()
@@ -909,7 +909,7 @@ for commands provided in the `ioccur-buffer'."
            (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
       ;; An hidden `ioccur-buffer' exists jump to it and reuse it.
-      (pop-to-buffer ioccur-buffer t)
+      (switch-to-buffer-other-window ioccur-buffer t)
       ;; `ioccur-buffer' doesn't exists or is visible, start searching
       ;; Creating a new `ioccur-buffer' or reusing the visible one after
       ;; erasing it.
@@ -929,7 +929,7 @@ for commands provided in the `ioccur-buffer'."
              str-no-prop)
         (set-text-properties 0 len nil init-str)
         (setq str-no-prop init-str)
-        (pop-to-buffer (get-buffer-create ioccur-buffer) t)
+        (switch-to-buffer-other-window (get-buffer-create ioccur-buffer) t)
         (ioccur-mode)
         (unwind-protect
              ;; Start incremental search.

commit dc0767c23c6a6bcbc85bc4bc935173fbf6efb147
Merge: 7f178bf 2e592bc
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 09:52:18 2010 +0200

    merge


commit 2e592bc1fb9401d2fa55aad544d3484a56c4fb58
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Oct 30 09:48:40 2010 +0200

    (ioccur-jump-without-quit,ioccur-scroll) Use switch-to-buffer-other-window 
instead of pop-to-buffer, specify also window conf arg

diff --git a/ioccur.el b/ioccur.el
index 1b10e19..070863a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -554,7 +554,8 @@ Move point to first occurence of `ioccur-pattern'."
 (defun ioccur-jump-without-quit ()
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
-  (when (ioccur-jump) (pop-to-buffer ioccur-buffer)))
+  (and (ioccur-jump ioccur-last-window-configuration)
+       (switch-to-buffer-other-window ioccur-buffer)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()
@@ -574,8 +575,8 @@ Move point to first occurence of `ioccur-pattern'."
   "Scroll `ioccur-buffer' and `ioccur-current-buffer' simultaneously."
   (ioccur-forward-line n)
   (ioccur-color-current-line)
-  (when (ioccur-jump)
-    (pop-to-buffer ioccur-buffer)))
+  (and (ioccur-jump ioccur-last-window-configuration)
+       (switch-to-buffer-other-window ioccur-buffer)))
 
 ;;;###autoload
 (defun ioccur-scroll-down ()

commit 79bad0a7b040a491206167e2642f639f6a1279c3
Author: Sam Stephenson <address@hidden>
Date:   Sat Sep 25 17:53:16 2010 -0500

    Add TODO for heredocs with embedded quotes.
    
    (Tried to fix them myself but I don't have the chops)

diff --git a/examples/edge.coffee b/examples/edge.coffee
index 75913c7..7682a58 100644
--- a/examples/edge.coffee
+++ b/examples/edge.coffee
@@ -8,3 +8,9 @@ console.log string
 
 string = 'Something with a \'single quote'
 console.log string
+
+# TODO
+heredoc = """
+  Heredoc with a " double quote
+"""
+console.log heredoc

commit c5831bbdf54d5b29c8401ce236e9ae894c679832
Author: Sam Stephenson <address@hidden>
Date:   Sat Sep 25 15:07:54 2010 -0500

    Fix for string literals with escaped quotes

diff --git a/coffee-mode.el b/coffee-mode.el
index f8c5710..19e2bde 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -228,6 +228,9 @@ path."
 ;; Define Language Syntax
 ;;
 
+;; String literals
+(defvar coffee-string-regexp 
"\"\\([^\\]\\|\\\\.\\)*?\"\\|'\\([^\\]\\|\\\\.\\)*?'")
+
 ;; Instance variables (implicit this)
 (defvar coffee-this-regexp "@\\(\\w\\|_\\)*\\|this")
 
@@ -281,7 +284,8 @@ path."
   ;; *Note*: order below matters. `coffee-keywords-regexp' goes last
   ;; because otherwise the keyword "state" in the function
   ;; "state_entry" would be highlighted.
-  `((,coffee-this-regexp . font-lock-variable-name-face)
+  `((,coffee-string-regexp . font-lock-string-face)
+    (,coffee-this-regexp . font-lock-variable-name-face)
     (,coffee-prototype-regexp . font-lock-variable-name-face)
     (,coffee-assign-regexp . font-lock-type-face)
     (,coffee-regexp-regexp . font-lock-constant-face)
@@ -580,7 +584,6 @@ line? Returns `t' or `nil'. See the README for more 
details."
 
   ;; single quote strings
   (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
-  (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
 
   ;; indentation
   (make-local-variable 'indent-line-function)
diff --git a/examples/edge.coffee b/examples/edge.coffee
index 3a60c7e..75913c7 100644
--- a/examples/edge.coffee
+++ b/examples/edge.coffee
@@ -2,3 +2,9 @@
 
 if string.match /\// or string.match /\x1b/ or string.match /a\/b/
   console.log "matched"
+
+string = "Something with a \"double quote"
+console.log string
+
+string = 'Something with a \'single quote'
+console.log string

commit 095e65ec95b69d6b2514632eae5267b33fccde3c
Author: Sam Stephenson <address@hidden>
Date:   Sat Sep 25 14:49:10 2010 -0500

    Fix for regex literals with escaped slashes

diff --git a/coffee-mode.el b/coffee-mode.el
index 266b308..f8c5710 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -247,7 +247,7 @@ path."
 (defvar coffee-boolean-regexp 
"\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\)\\b")
 
 ;; Regular Expressions
-(defvar coffee-regexp-regexp "\\/.+?\\/")
+(defvar coffee-regexp-regexp "\\/\\([^\\]\\|\\\\.\\)+?\\/")
 
 ;; JavaScript Keywords
 (defvar coffee-js-keywords
diff --git a/examples/edge.coffee b/examples/edge.coffee
new file mode 100644
index 0000000..3a60c7e
--- /dev/null
+++ b/examples/edge.coffee
@@ -0,0 +1,4 @@
+# Edge cases
+
+if string.match /\// or string.match /\x1b/ or string.match /a\/b/
+  console.log "matched"

commit 5c5a414d5e4e5b031fea2aea8376ed9a0871e652
Author: Sam Stephenson <address@hidden>
Date:   Sat Sep 25 14:25:17 2010 -0500

    Recognize 0.9.0 assignment syntax

diff --git a/coffee-mode.el b/coffee-mode.el
index eb69449..266b308 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -235,7 +235,7 @@ path."
 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| 
\\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
 ;; Assignment
-(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
+(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\)[:=]")
 
 ;; Lambda
 (defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")
diff --git a/examples/basic.coffee b/examples/basic.coffee
index f434f81..d275632 100644
--- a/examples/basic.coffee
+++ b/examples/basic.coffee
@@ -1,32 +1,32 @@
 # These examples are taken from
 # http://jashkenas.github.com/coffee-script/
 
-song: ["do", "re", "mi", "fa", "so"]
+song = ["do", "re", "mi", "fa", "so"]
 
-ages: {
+ages = {
   max: 10
   ida: 9
   tim: 11
 }
 
-matrix: [
+matrix = [
   1, 0, 1
   0, 0, 1
   1, 1, 0
 ]
 
-eldest: if 24 > 21 then "Liz" else "Ike"
+eldest = if 24 > 21 then "Liz" else "Ike"
 
-six: (one: 1) + (two: 2) + (three: 3)
+six = (one = 1) + (two = 2) + (three = 3)
 
-My.mood: greatly_improved if true
+My.mood = greatly_improved if true
 
 # Unfancy JavaScript
 if happy and knows_it
   cha_cha_cha()
   false
 
-Account: (customer, cart) ->
+Account = (customer, cart) ->
   @customer: customer
   @cart: cart
 
@@ -56,8 +56,8 @@ class Horse extends Animal
     alert "Galloping..."
     super 45
 
-sam: new Snake "Sammy the Python"
-tom: new Horse "Tommy the Palomino"
+sam = new Snake "Sammy the Python"
+tom = new Horse "Tommy the Palomino"
 
 sam.move()
 tom.move()
@@ -65,14 +65,14 @@ if car.speed < speed_limit then accelerate()
 
 print "My name is " + @name
 
-gold: silver: the_field: "unknown"
+gold = silver = the_field = "unknown"
 
-award_medals: (first, second, rest...) ->
+award_medals = (first, second, rest...) ->
   gold:       first
   silver:     second
   the_field:  rest
 
-contenders: [
+contenders = [
   "Michael Phelps"
   "Liu Xiang"
 ]
@@ -86,14 +86,14 @@ alert "The Field: " + the_field
 # Eat lunch.
 # what up
 # love it.
-lunch: eat food for food in ['toast', 'cheese', 'wine']
+lunch = eat food for food in ['toast', 'cheese', 'wine']
 
 $('#demo').click ->
   asd
 # sup
   # asd
   # asdasd
-blah: true
+blah = true
 
 okay
 
@@ -103,12 +103,12 @@ for roid in asteroids
   for roid2 in asteroids when roid isnt roid2
     roid.explode() if roid.overlaps roid2
 
-years_old: {max: 10, ida: 9, tim: 11}
+years_old = max: 10, ida: 9, tim: 11
 
-ages: for child, age of years_old
+ages = for child, age of years_old
   child + " is " + age
 
-grade: (student) ->
+grade = (student) ->
   if student.excellent_work
     "A+"
   else if student.okay_stuff
diff --git a/examples/imenu.coffee b/examples/imenu.coffee
index fc17c5d..fdf0025 100644
--- a/examples/imenu.coffee
+++ b/examples/imenu.coffee
@@ -1,29 +1,28 @@
 # Testing imenu
-regexp: /asdas/
-two: 4 / 2
+regexp = /asdas/
+two = 4 / 2
 
-minus: (x, y) -> x - y
+minus = (x, y) -> x - y
 
-String::length: -> 10
+String::length = -> 10
 
 class Person
   print: ->
     print 'My name is ' + this.name + '.'
 
-app = {
+app =
   window:  {width: 200, height: 200}
   para:    'Welcome.'
   button:  'OK'
-}
 
-block: ->
+block = ->
   print('potion')
 
-Please: {}
-Please.print: (word) ->
+Please = {}
+Please.print = (word) ->
   print(word)
 
-HomePage::get: (url) ->
+HomePage::get = (url) ->
   session: url.query.session if url.query?
 
 class Policeman extends Person

commit 7f178bf45b1d7e55e4f6c1cced2eee6611968795
Merge: 7cf2b81 9941a61
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 17 15:44:34 2010 +0200

    merge branchs


commit 9941a6143b36ae4ed1cd2f834f38e8804d8e3924
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Sep 16 20:27:57 2010 +0200

    (ioccur-read-search-input) Maybe restart timer when toggle regexp/litteral 
search.

diff --git a/ioccur.el b/ioccur.el
index c5bdebf..1b10e19 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -736,6 +736,7 @@ START-POINT is the point where we start searching in 
buffer."
                  (?\C-s                         ; Toggle split window.
                   (ioccur-split-window) t)
                  ((?\C-: ?\C-l)                 ; Toggle regexp/litteral 
search.
+                  (start-timer)
                   (if (eq ioccur-search-function 're-search-forward)
                       (setq ioccur-search-function 'search-forward)
                       (setq ioccur-search-function 're-search-forward)) t)

commit 73bba83a7538eea674c3900e193686794786c14b
Merge: 7cf2b81 41a9ec5
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Sep 16 09:59:11 2010 +0200

    Merge tags in dev branch.


commit 7cf2b810fe7de1d96a15dabce37fbca3219db033
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Sep 16 09:58:14 2010 +0200

    Added tag V-2.0 for changeset c7f96148ecbc

commit 954c5dbd0f3430121338c811e91bac45021f9740
Merge: 41a9ec5 4a89fd9
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Sep 16 09:57:36 2010 +0200

    Merge dev in default.


commit 41a9ec5330168bbbba749a1d66f7bb57276355d2
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Sep 13 11:20:02 2010 +0200

    Highlight match line by line, fix bug that don't highlight match when match 
is whole line.
    
    (ioccur-highlight-match-on-line) new.
    (ioccur-print-results) Send last match and regexp to *-print-line.
    (ioccur-print-line) take four args now.

diff --git a/ioccur.el b/ioccur.el
index 46ed64d..c5bdebf 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -299,18 +299,39 @@ Special commands:
          for count from 0
          when (funcall ioccur-search-function regexp (point-at-eol) t)
          do (ioccur-print-line
-             (buffer-substring (point-at-bol) (point-at-eol)) count)
+             (buffer-substring (point-at-bol) (point-at-eol))
+             count (match-string 0) regexp)
          do (forward-line 1)))))
 
-(defun ioccur-print-line (line nline)
+(defun ioccur-print-line (line nline match regexp)
   "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
-    (let ((lineno     (int-to-string (1+ nline)))
-          (trunc-line (ioccur-truncate-line line)))
+    (let* ((lineno             (int-to-string (1+ nline)))
+           (trunc-line         (ioccur-truncate-line line))
+           (whole-line-matched (string= match line)))
       (incf ioccur-count-occurences)
       (insert " " (propertize lineno 'face 'ioccur-num-line-face
                               'help-echo line)
-              ":" trunc-line "\n"))))
+              ":" trunc-line "\n")
+      (when ioccur-highlight-match-p
+        (if whole-line-matched ; Regexp match the whole line, highlight it.
+            (save-excursion
+              (forward-line -1) (re-search-forward "\\(\\s-[0-9]+:\\)" nil t)
+              (put-text-property (point) (point-at-eol)
+                                 'face 'ioccur-match-face))
+            (ioccur-highlight-match-on-line regexp))))))
+
+(defun ioccur-highlight-match-on-line (regexp)
+  "Highlight all occurences of REGEXP on precedent line."
+  (save-excursion
+    (forward-line -1)
+    (while (and (funcall ioccur-search-function regexp (point-at-eol) t)
+                ;; If length of match is null exit loop.
+                ;; e.g when searching "^".
+                (> (- (match-end 0) (match-beginning 0)) 0))
+      (put-text-property (match-beginning 0) (point)
+                         'face 'ioccur-match-face))))
+
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
   "Remove indentation in LINE and truncate modified LINE of num COLUMNS.
@@ -815,9 +836,7 @@ M-p/n or tab/S-tab History."))
                     (propertize
                      (format " in %s" ioccur-current-buffer)
                      'face 'underline) "\n\n")
-            (ioccur-color-current-line)
-            (when ioccur-highlight-match-p
-              (ioccur-highlight-match (point) regexp))))))
+            (ioccur-color-current-line)))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."
@@ -991,19 +1010,7 @@ of matched line in `ioccur-current-buffer'."
             (make-overlay (point-at-bol) (1+ (point-at-eol)))))
   (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
-(defun ioccur-highlight-match (beg regexp)
-  "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
-  (save-excursion
-    (goto-char beg)
-    (while (and (funcall ioccur-search-function regexp nil t)
-                (not (eobp))
-                ;; If length of match is null exit loop.
-                ;; e.g when searching "^".
-                (> (- (match-end 0) (match-beginning 0)) 0))
-      (put-text-property (match-beginning 0) (point)
-                         'face 'ioccur-match-face))))
             
-
 (provide 'ioccur)
 
 ;;; ioccur.el ends here

commit 66139ffae5f96edc58b630b63aa371368862f849
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Sep 12 09:22:42 2010 +0200

    (ioccur-beginning-of-buffer, ioccur-end-of-buffer) New, that have been 
implemented in the past but never commited!

diff --git a/ioccur.el b/ioccur.el
index f64fb04..46ed64d 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -67,6 +67,8 @@
     (define-key map (kbd "C-p")      'ioccur-precedent-line)
     (define-key map (kbd "R")        'ioccur-restart)
     (define-key map (kbd "C-|")      'ioccur-split-window)
+    (define-key map (kbd "M-<")      'ioccur-beginning-of-buffer)
+    (define-key map (kbd "M->")      'ioccur-end-of-buffer)
     map)
   "Keymap used for ioccur commands.")
 
@@ -463,7 +465,7 @@ Goto NUMLINE."
   (let (pos)
     (save-excursion
       (forward-line n) (forward-line 0)
-      (when (looking-at "^ [0-9]+")
+      (when (looking-at "^\\s-[0-9]+:")
         (forward-line 0) (setq pos (point))))
   (when pos (goto-char pos) (ioccur-color-current-line))))
 
@@ -479,6 +481,25 @@ Goto NUMLINE."
   (interactive)
   (ioccur-forward-line -1))
 
+;;;###autoload
+(defun ioccur-beginning-of-buffer ()
+  "Goto beginning of `ioccur-buffer'."
+  (interactive)
+  (when (looking-at "^\\s-[0-9]+:")
+    (goto-char (point-min))
+    (re-search-forward "^\\s-[0-9]+:" nil t)
+    (forward-line 0)
+    (ioccur-color-current-line)))
+
+;;;###autoload
+(defun ioccur-end-of-buffer ()
+  "Go to end of `ioccur-buffer'."
+  (interactive)
+  (when (looking-at "^\\s-[0-9]+:")
+    (goto-char (point-max))
+    (forward-line -1)
+    (ioccur-color-current-line)))
+
 (defun ioccur-jump (&optional win-conf)
   "Jump to line in other buffer and put an overlay on it.
 Move point to first occurence of `ioccur-pattern'."
@@ -663,6 +684,12 @@ START-POINT is the point where we start searching in 
buffer."
                  ((up ?\C-p)                    ; Precedent line.
                   (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
+                 (?\M-<                         ; Beginning of buffer.
+                  (when (ioccur-beginning-of-buffer)
+                    (stop-timer)) t)
+                 (?\M->                         ; End of buffer.
+                  (when (ioccur-end-of-buffer)
+                    (stop-timer)) t)
                  ((?\C-d C-down)                ; Scroll both windows down.
                   (stop-timer) (ioccur-scroll-down) t)
                  ((?\C-u C-up)                  ; Scroll both windows up.
@@ -764,6 +791,7 @@ C-s                Toggle split window.\n
 C-:/l              Toggle regexp/litteral search.\n
 C-down or C-u      Follow in other buffer.\n
 C-up/d or C-d      Follow in other buffer.\n
+M-<, M->           Beginning and end of buffer.\n
 M-p/n or tab/S-tab History."))
            wrong-regexp)
     (if (string= regexp "")
@@ -827,8 +855,9 @@ C-:            Toggle regexp/litteral search.
 C-down         Follow in other buffer.
 C-up           Follow in other buffer.
 M-p/n          Precedent and next `ioccur-history' element.
+M-<, M->       Beginning and end of buffer.
 
-Unlike minibuffer history, ioccur history is a ring (no end):
+Unlike minibuffer history, cycling in ioccur history have no end:
 
 M-p ,-->A B C D E F G H I---,
     |                       |
@@ -838,7 +867,6 @@ M-n ,-->I H G F E D C B A---,
     |                       |
     `---A B C D E F G H I<--'
 
-If a region is active, search only in this region.
 
 Special NOTE for terms:
 =======================

commit 7e59a2c629b49807093a579f52aa18dc0eb81f9a
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Sep 11 23:54:47 2010 +0200

    (ioccur-truncate-line) Fix.

diff --git a/ioccur.el b/ioccur.el
index fa06baa..f64fb04 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -313,13 +313,16 @@ Special commands:
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
   "Remove indentation in LINE and truncate modified LINE of num COLUMNS.
 COLUMNS default value is `ioccur-length-line'.
-If COLUMNS is nil return LINE.
-If COLUMNS is 0 only remove indentation.
+If COLUMNS is nil return original indented LINE.
+If COLUMNS is 0 only remove indentation in LINE.
 So just set `ioccur-length-line' to nil if you don't want lines truncated."
-  (when (string-match "^[[:blank:]]*" line)
-    (setq line (replace-match "" nil nil line)))
-  (if (and columns (> (length line) columns))
-      (substring line 0 columns) line))
+  (let ((old-line line))
+    (when (string-match "^[[:blank:]]*" line)
+      ;; Remove tab and spaces at beginning of LINE.
+      (setq line (replace-match "" nil nil line)))
+    (if (and columns (> columns 0) (> (length line) columns))
+        (substring line 0 columns)
+        (if columns line old-line))))
 
 (defun ioccur-buffer-contain (buffer regexp)
   "Return BUFFER if it contain an occurence of REGEXP."

commit 12747c2d9293eac46a39696aba5440aa016da19c
Author: mooz <address@hidden>
Date:   Mon Sep 6 00:38:57 2010 +0900

    Added description of indentation style

diff --git a/README.md b/README.md
index 2487c82..19cd7e1 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,32 @@ Support for expression closure in property value
         fire: function () _fire()
     };
 
+Supported more popular indentation style
+----------------------------------------
+
+When js2-consistent-level-indent-inner-bracket-p is non-nil
+    
+    [foo, bar, baz].forEach(function (v) {
+        if (validate(v))
+            process(v);
+    });
+    
+    [a, b, c].some(function (v) {
+        return validate(v);
+    });
+
+When js2-consistent-level-indent-inner-bracket-p is nil
+(Same as original js2-mode's indentation)
+
+    [foo, bar, baz].forEach(function (v) {
+                                if (validate(v))
+                                    process(v);
+                            });
+    
+    [a, b, c].some(function (v) {
+                       return validate(v);
+                   });
+
 Fixed the odd indentation of "else if" with no braces
 -----------------------------------------------------
 

commit 5dacf96e7813ae83a1f26b388f95bad90007c140
Author: mooz <address@hidden>
Date:   Mon Sep 6 00:17:23 2010 +0900

    Added option js2-consistent-level-indent-inner-bracket-p which makes 
indentation more normally.

diff --git a/js2-mode.el b/js2-mode.el
index 03aee99..80a5f28 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -226,6 +226,12 @@ See the function `js2-bounce-indent' for details."
   :type 'boolean
   :group 'js2-mode)
 
+(defcustom js2-consistent-level-indent-inner-bracket-p t
+  "Non-nil to make indentation level inner bracket consistent,
+regardless of the beginning bracket position."
+  :group 'js2-mode
+  :type 'boolean)
+
 (defcustom js2-indent-on-enter-key nil
   "Non-nil to have Enter/Return key indent the line.
 This is unusual for Emacs modes but common in IDEs like Eclipse."
@@ -9854,7 +9860,8 @@ In particular, return the buffer position of the first 
`for' kwd."
             (when (save-excursion (skip-chars-backward " \t)")
                                   (looking-at ")"))
               (backward-list))
-            (if (nth 1 p)
+            (if (and (nth 1 p)
+                     (not js2-consistent-level-indent-inner-bracket-p))
                 (progn (goto-char (1+ (nth 1 p)))
                        (skip-chars-forward " \t"))
               (back-to-indentation))

commit d775bec0e41cbfa689c0387ef92c19de789acaa2
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 3 10:45:45 2010 +0200

    Use a different face for matches.
    (ioccur-match-face) new

diff --git a/ioccur.el b/ioccur.el
index cf6e929..fa06baa 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -159,7 +159,12 @@ Set it to non--nil if menu disapear or if keys are echoing 
in minibuffer.")
 
 (defface ioccur-regexp-face
     '((t (:background "DeepSkyBlue" :underline t)))
-  "Face for highlight found regexp in incremental buffer."
+  "Face for highlight found regexp in `ioccur-buffer'."
+  :group 'ioccur-faces)
+
+(defface ioccur-match-face
+    '((t (:background "DeepSkyBlue")))
+  "Face for highlight matches in `ioccur-buffer'."
   :group 'ioccur-faces)
 
 (defface ioccur-num-line-face
@@ -965,7 +970,7 @@ of matched line in `ioccur-current-buffer'."
                 ;; e.g when searching "^".
                 (> (- (match-end 0) (match-beginning 0)) 0))
       (put-text-property (match-beginning 0) (point)
-                         'face 'ioccur-regexp-face))))
+                         'face 'ioccur-match-face))))
             
 
 (provide 'ioccur)

commit dce5d07fde2566c416de11140f6795b444aab474
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Sep 3 08:14:53 2010 +0200

    (ioccur-truncate-line) Simplify.

diff --git a/ioccur.el b/ioccur.el
index 57e9ceb..cf6e929 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -301,9 +301,8 @@ Special commands:
     (let ((lineno     (int-to-string (1+ nline)))
           (trunc-line (ioccur-truncate-line line)))
       (incf ioccur-count-occurences)
-      (insert " " (propertize
-                   lineno 'face 'ioccur-num-line-face
-                   'help-echo line)
+      (insert " " (propertize lineno 'face 'ioccur-num-line-face
+                              'help-echo line)
               ":" trunc-line "\n"))))
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
@@ -312,14 +311,10 @@ COLUMNS default value is `ioccur-length-line'.
 If COLUMNS is nil return LINE.
 If COLUMNS is 0 only remove indentation.
 So just set `ioccur-length-line' to nil if you don't want lines truncated."
-  (let* ((bol-reg (if (string-match "^\t" line)
-                      "\\(^\t*\\)" "\\(^ *\\)"))
-         (ltp     (replace-regexp-in-string bol-reg "" line)))
-    (cond ((and columns (> (length ltp) columns))
-           (substring ltp 0 columns))
-          ((and columns (< (length ltp) columns))
-           ltp)
-          (t line))))
+  (when (string-match "^[[:blank:]]*" line)
+    (setq line (replace-match "" nil nil line)))
+  (if (and columns (> (length line) columns))
+      (substring line 0 columns) line))
 
 (defun ioccur-buffer-contain (buffer regexp)
   "Return BUFFER if it contain an occurence of REGEXP."
@@ -865,7 +860,6 @@ for commands provided in the `ioccur-buffer'."
                            (if (stringp initial-input)
                                initial-input (thing-at-point 'symbol))
                            ""))
-             ;
              (len      (length init-str))
              (curpos   (point))
              (cur-mode (with-current-buffer ioccur-current-buffer

commit ab12843ea64fbaba50aed73e89071edf33ff9479
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Sep 1 08:18:21 2010 +0200

    (ioccur-quit) Fix docstring, no code change.

diff --git a/ioccur.el b/ioccur.el
index f795cae..57e9ceb 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -440,7 +440,7 @@ See `ioccur-find-buffer-matching1'."
 
 ;;;###autoload
 (defun ioccur-quit ()
-  "Quit and kill ioccur buffer."
+  "Quit `ioccur-buffer'."
   (interactive)
   (let ((pos (with-current-buffer ioccur-current-buffer (point))))
     (when ioccur-match-overlay

commit 38d4937b7e204a5f145dfa2316b7029d06c4cb42
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Sep 1 08:00:58 2010 +0200

    (ioccur-quit) Fix window-config.

diff --git a/ioccur.el b/ioccur.el
index 79399e3..f795cae 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -442,11 +442,13 @@ See `ioccur-find-buffer-matching1'."
 (defun ioccur-quit ()
   "Quit and kill ioccur buffer."
   (interactive)
-  (when ioccur-match-overlay
-    (delete-overlay ioccur-match-overlay))
-  (quit-window)
-  (other-window 1)
-  (delete-other-windows))
+  (let ((pos (with-current-buffer ioccur-current-buffer (point))))
+    (when ioccur-match-overlay
+      (delete-overlay ioccur-match-overlay))
+    (quit-window)
+    (set-window-configuration ioccur-last-window-configuration)
+    (pop-to-buffer ioccur-current-buffer)
+    (goto-char pos)))
 
 (defun ioccur-goto-line (numline)
   "Non--interactive version of `goto-line'.

commit 295bd46a138a3d4bb7b5bf134ebeb3af1dd449e3
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Sep 1 07:35:14 2010 +0200

    (ioccur) Fix window-configuration when C-g.

diff --git a/ioccur.el b/ioccur.el
index e784aca..79399e3 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -499,7 +499,6 @@ Move point to first occurence of `ioccur-pattern'."
   "Jump to line in other buffer and quit search buffer."
   (interactive)
   (when (ioccur-jump ioccur-last-window-configuration)
-    ;(unless win-conf (delete-other-windows))
     (sit-for 0.3)
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
@@ -525,7 +524,7 @@ Move point to first occurence of `ioccur-pattern'."
     (scroll-other-window -1)))
 
 (defun ioccur-scroll (n)
-  "Scroll `ioccur-buffer' and `ioccur-current-buffer' synchronously."
+  "Scroll `ioccur-buffer' and `ioccur-current-buffer' simultaneously."
   (ioccur-forward-line n)
   (ioccur-color-current-line)
   (when (ioccur-jump)
@@ -533,13 +532,13 @@ Move point to first occurence of `ioccur-pattern'."
 
 ;;;###autoload
 (defun ioccur-scroll-down ()
-  "Scroll down `ioccur-buffer' and `ioccur-current-buffer' synchronously."
+  "Scroll down `ioccur-buffer' and `ioccur-current-buffer' simultaneously."
   (interactive)
   (ioccur-scroll 1))
 
 ;;;###autoload
 (defun ioccur-scroll-up ()
-  "Scroll up `ioccur-buffer' and `ioccur-current-buffer' synchronously."
+  "Scroll up `ioccur-buffer' and `ioccur-current-buffer' simultaneously."
   (interactive)
   (ioccur-scroll -1))
 
@@ -892,14 +891,15 @@ for commands provided in the `ioccur-buffer'."
               (setq ioccur-quit-flag t))
             (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
                    (kill-buffer ioccur-buffer)
-                   (switch-to-buffer ioccur-current-buffer)
+                   (pop-to-buffer ioccur-current-buffer)
                    (when ioccur-match-overlay
                      (delete-overlay ioccur-match-overlay))
-                   (delete-other-windows) (goto-char curpos)
+                   (set-window-configuration ioccur-last-window-configuration)
+                   (goto-char curpos)
                    (ioccur-send-message)
                    ;; If `ioccur-message' is non--nil, thats mean we exit
                    ;; with a specific action other than `C-g',
-                   ;; so we save history.
+                   ;; e.g kill-as-sexp, so we save history.
                    (when ioccur-message (ioccur-save-history)))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
                    (ioccur-jump-and-quit)

commit 8be228775655eb55d3615dd29c0b12121fba95bc
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Sep 1 07:13:27 2010 +0200

    Fix scrolling, always scroll in named buffer.

diff --git a/ioccur.el b/ioccur.el
index 6576055..e784aca 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -508,36 +508,38 @@ Move point to first occurence of `ioccur-pattern'."
 (defun ioccur-jump-without-quit ()
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
-  (when (ioccur-jump) (other-window 1)))
+  (when (ioccur-jump) (pop-to-buffer ioccur-buffer)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()
   "Scroll other window down."
   (interactive)
-  (scroll-other-window 1))
+  (let ((other-window-scroll-buffer ioccur-current-buffer))
+    (scroll-other-window 1)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-up ()
   "Scroll other window up."
   (interactive)
-  (scroll-other-window -1))
+  (let ((other-window-scroll-buffer ioccur-current-buffer))
+    (scroll-other-window -1)))
 
 (defun ioccur-scroll (n)
-  "Scroll other buffer N lines and move overlay accordingly."
+  "Scroll `ioccur-buffer' and `ioccur-current-buffer' synchronously."
   (ioccur-forward-line n)
   (ioccur-color-current-line)
   (when (ioccur-jump)
-    (other-window 1)))
+    (pop-to-buffer ioccur-buffer)))
 
 ;;;###autoload
 (defun ioccur-scroll-down ()
-  "Scroll other buffer down."
+  "Scroll down `ioccur-buffer' and `ioccur-current-buffer' synchronously."
   (interactive)
   (ioccur-scroll 1))
 
 ;;;###autoload
 (defun ioccur-scroll-up ()
-  "Scroll other buffer up."
+  "Scroll up `ioccur-buffer' and `ioccur-current-buffer' synchronously."
   (interactive)
   (ioccur-scroll -1))
 

commit 68a7c1cd60deb3223a5222bfbfe71fb11ad28bdd
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Sep 1 06:48:17 2010 +0200

    Keep window configuration when restart.

diff --git a/ioccur.el b/ioccur.el
index 7cca897..6576055 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -202,6 +202,9 @@ Set it to non--nil if menu disapear or if keys are echoing 
in minibuffer.")
 (defvar ioccur-search-function ioccur-default-search-function)
 ;; Message to send when ioccur exit
 (defvar ioccur-message nil)
+;; Store last window-configuration
+(defvar ioccur-last-window-configuration nil)
+
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -430,9 +433,10 @@ See `ioccur-find-buffer-matching1'."
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
   (when (eq major-mode 'ioccur-mode)
-    (pop-to-buffer ioccur-current-buffer);(other-window 1)
+    (pop-to-buffer ioccur-current-buffer)
     (kill-buffer ioccur-buffer)
-    (delete-other-windows) (ioccur)))
+    (set-window-configuration ioccur-last-window-configuration)
+    (ioccur)))
 
 ;;;###autoload
 (defun ioccur-quit ()
@@ -794,7 +798,6 @@ M-p/n or tab/S-tab History."))
   "Send message defined in `ioccur-message'."
   (message ioccur-message))
 
-(defvar ioccur-last-window-configuration nil)
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.

commit 534910abc712d2120b75072eda85dc43d53c496b
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Aug 31 22:43:46 2010 +0200

    Improve window-confuguration handling.
    
    (ioccur-last-window-configuration) new

diff --git a/ioccur.el b/ioccur.el
index 8193406..7cca897 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -429,8 +429,9 @@ See `ioccur-find-buffer-matching1'."
   "Restart `ioccur' from `ioccur-buffer'.
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
-  (when (and (eq major-mode 'ioccur-mode) (eq (count-windows) 2))
-    (other-window 1) (kill-buffer ioccur-buffer)
+  (when (eq major-mode 'ioccur-mode)
+    (pop-to-buffer ioccur-current-buffer);(other-window 1)
+    (kill-buffer ioccur-buffer)
     (delete-other-windows) (ioccur)))
 
 ;;;###autoload
@@ -479,7 +480,7 @@ Move point to first occurence of `ioccur-pattern'."
     (unless (string= line "")
       (if win-conf
           (set-window-configuration win-conf)
-          (pop-to-buffer ioccur-current-buffer t))
+          (pop-to-buffer ioccur-current-buffer))
       (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos) (recenter)
       ;; Go to beginning of first occurence in this line
@@ -490,11 +491,11 @@ Move point to first occurence of `ioccur-pattern'."
       (ioccur-color-matched-line))))
 
 ;;;###autoload
-(defun ioccur-jump-and-quit (&optional win-conf)
+(defun ioccur-jump-and-quit ()
   "Jump to line in other buffer and quit search buffer."
   (interactive)
-  (when (ioccur-jump win-conf)
-    (unless win-conf (delete-other-windows))
+  (when (ioccur-jump ioccur-last-window-configuration)
+    ;(unless win-conf (delete-other-windows))
     (sit-for 0.3)
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
@@ -793,6 +794,7 @@ M-p/n or tab/S-tab History."))
   "Send message defined in `ioccur-message'."
   (message ioccur-message))
 
+(defvar ioccur-last-window-configuration nil)
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.
@@ -844,6 +846,7 @@ for commands provided in the `ioccur-buffer'."
   (message "Fontifying buffer...Please wait it could be long.")
   (jit-lock-fontify-now) (message nil)
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
+  (setq ioccur-last-window-configuration (current-window-configuration))
   (if (and (not initial-input)
            (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
@@ -856,7 +859,7 @@ for commands provided in the `ioccur-buffer'."
                            (if (stringp initial-input)
                                initial-input (thing-at-point 'symbol))
                            ""))
-             (win-conf (current-window-configuration))
+             ;
              (len      (length init-str))
              (curpos   (point))
              (cur-mode (with-current-buffer ioccur-current-buffer
@@ -894,10 +897,11 @@ for commands provided in the `ioccur-buffer'."
                    ;; so we save history.
                    (when ioccur-message (ioccur-save-history)))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
-                   (ioccur-jump-and-quit win-conf) (kill-buffer ioccur-buffer)
+                   (ioccur-jump-and-quit)
+                   (kill-buffer ioccur-buffer)
                    (ioccur-send-message) (ioccur-save-history))
                   (t                   ; Jump keeping `ioccur-buffer'.
-                   (ioccur-jump) (other-window 1) (ioccur-save-history)))
+                   (ioccur-jump) (pop-to-buffer ioccur-buffer) 
(ioccur-save-history)))
             ;; Maybe reenable `wdired-mode'.
             (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
             (setq ioccur-count-occurences 0)

commit ba8b610f13ecfe6c01508d9f25572456db4d4673
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 30 20:07:51 2010 +0200

    (ioccur-jump) remove now unused test, fix long lines.

diff --git a/ioccur.el b/ioccur.el
index 5087770..8193406 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -476,9 +476,10 @@ Move point to first occurence of `ioccur-pattern'."
          (pos            (string-to-number line))
          (back-search-fn (if (eq ioccur-search-function 're-search-forward)
                              're-search-backward 'search-backward)))
-    (unless (or (string= line "")
-                (string= line "Ioccur"))
-      (if win-conf (set-window-configuration win-conf) (pop-to-buffer 
ioccur-current-buffer t))
+    (unless (string= line "")
+      (if win-conf
+          (set-window-configuration win-conf)
+          (pop-to-buffer ioccur-current-buffer t))
       (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos) (recenter)
       ;; Go to beginning of first occurence in this line

commit fd5498ff474a2be4db134b6f10eda548b8c106d9
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 30 19:51:57 2010 +0200

    Always save and restore window configuration when exit and quit.
    
    (ioccur-restart) Kill ioccur-buffer and delete other windows before calling 
ioccur.
    (ioccur-jump) maybe restore window configuration, take an optional arg.
    (ioccur-jump-and-quit) call ioccur-jump with extra arg.

diff --git a/ioccur.el b/ioccur.el
index 2631c86..5087770 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -430,7 +430,8 @@ See `ioccur-find-buffer-matching1'."
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
   (when (and (eq major-mode 'ioccur-mode) (eq (count-windows) 2))
-    (other-window 1) (ioccur)))
+    (other-window 1) (kill-buffer ioccur-buffer)
+    (delete-other-windows) (ioccur)))
 
 ;;;###autoload
 (defun ioccur-quit ()
@@ -468,7 +469,7 @@ Goto NUMLINE."
   (interactive)
   (ioccur-forward-line -1))
 
-(defun ioccur-jump ()
+(defun ioccur-jump (&optional win-conf)
   "Jump to line in other buffer and put an overlay on it.
 Move point to first occurence of `ioccur-pattern'."
   (let* ((line           (buffer-substring (point-at-bol) (point-at-eol)))
@@ -477,7 +478,7 @@ Move point to first occurence of `ioccur-pattern'."
                              're-search-backward 'search-backward)))
     (unless (or (string= line "")
                 (string= line "Ioccur"))
-      (pop-to-buffer ioccur-current-buffer t)
+      (if win-conf (set-window-configuration win-conf) (pop-to-buffer 
ioccur-current-buffer t))
       (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos) (recenter)
       ;; Go to beginning of first occurence in this line
@@ -488,11 +489,11 @@ Move point to first occurence of `ioccur-pattern'."
       (ioccur-color-matched-line))))
 
 ;;;###autoload
-(defun ioccur-jump-and-quit ()
+(defun ioccur-jump-and-quit (&optional win-conf)
   "Jump to line in other buffer and quit search buffer."
   (interactive)
-  (when (ioccur-jump)
-    (delete-other-windows)
+  (when (ioccur-jump win-conf)
+    (unless win-conf (delete-other-windows))
     (sit-for 0.3)
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
@@ -845,14 +846,16 @@ for commands provided in the `ioccur-buffer'."
   (if (and (not initial-input)
            (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
-      ;; An hidden `ioccur-buffer' exists jump to it.
+      ;; An hidden `ioccur-buffer' exists jump to it and reuse it.
       (pop-to-buffer ioccur-buffer t)
-      ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
+      ;; `ioccur-buffer' doesn't exists or is visible, start searching
+      ;; Creating a new `ioccur-buffer' or reusing the visible one after
+      ;; erasing it.
       (let* ((init-str (if initial-input
                            (if (stringp initial-input)
-                               initial-input
-                               (thing-at-point 'symbol))
+                               initial-input (thing-at-point 'symbol))
                            ""))
+             (win-conf (current-window-configuration))
              (len      (length init-str))
              (curpos   (point))
              (cur-mode (with-current-buffer ioccur-current-buffer
@@ -890,7 +893,7 @@ for commands provided in the `ioccur-buffer'."
                    ;; so we save history.
                    (when ioccur-message (ioccur-save-history)))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
-                   (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
+                   (ioccur-jump-and-quit win-conf) (kill-buffer ioccur-buffer)
                    (ioccur-send-message) (ioccur-save-history))
                   (t                   ; Jump keeping `ioccur-buffer'.
                    (ioccur-jump) (other-window 1) (ioccur-save-history)))

commit d64a2df3d02b01fb896ea6f08880360e9066dfbc
Merge: df99fe1 4a89fd9
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 28 20:40:43 2010 +0200

    Merge tags in dev.


commit 4a89fd9f634f98ab9bf1a5db43f82b1bc024bea7
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 28 20:40:00 2010 +0200

    Added tag V-1.9 for changeset 3d4b0bdb7c4c

commit aa22df54583fd7deeee3f8f9c30f372f0f7aadbf
Merge: b5678a9 df99fe1
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 28 20:38:59 2010 +0200

    Merge from dev.


commit df99fe1f5df6fe3ec101762c3a2d1c58b2cc483f
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 28 18:36:01 2010 +0200

    (ioccur-truncate-line) Allow to display whole line when ioccur-length-line 
is nil.

diff --git a/ioccur.el b/ioccur.el
index 3748983..2631c86 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -101,7 +101,9 @@ Set it to nil to remove doc in mode-line."
   :type  'string)
 
 (defcustom ioccur-length-line 80
-  "*Length of the line displayed in ioccur buffer."
+  "*Length of the line displayed in ioccur buffer.
+When set to nil lines displayed in `ioccur-buffer' will not be modified.
+See `ioccur-truncate-line'."
   :group 'ioccur
   :type 'integer)
 
@@ -302,13 +304,19 @@ Special commands:
               ":" trunc-line "\n"))))
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
-  "Remove indentation and truncate LINE of num COLUMNS.
-COLUMNS default value is `ioccur-length-line'."
+  "Remove indentation in LINE and truncate modified LINE of num COLUMNS.
+COLUMNS default value is `ioccur-length-line'.
+If COLUMNS is nil return LINE.
+If COLUMNS is 0 only remove indentation.
+So just set `ioccur-length-line' to nil if you don't want lines truncated."
   (let* ((bol-reg (if (string-match "^\t" line)
                       "\\(^\t*\\)" "\\(^ *\\)"))
          (ltp     (replace-regexp-in-string bol-reg "" line)))
-    (if (> (length ltp) ioccur-length-line)
-        (substring ltp 0 ioccur-length-line) ltp)))
+    (cond ((and columns (> (length ltp) columns))
+           (substring ltp 0 columns))
+          ((and columns (< (length ltp) columns))
+           ltp)
+          (t line))))
 
 (defun ioccur-buffer-contain (buffer regexp)
   "Return BUFFER if it contain an occurence of REGEXP."

commit 2e09da12de8c33bab2c5e6fed2324ada9e9defba
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Aug 27 09:13:50 2010 +0200

    Regression: Fall back to precedent approach as parsing line by line to 
highlight regexp is not faster.

diff --git a/ioccur.el b/ioccur.el
index d9121ad..3748983 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -287,21 +287,10 @@ Special commands:
          for count from 0
          when (funcall ioccur-search-function regexp (point-at-eol) t)
          do (ioccur-print-line
-             (buffer-substring (point-at-bol) (point-at-eol)) count regexp)
+             (buffer-substring (point-at-bol) (point-at-eol)) count)
          do (forward-line 1)))))
 
-(defun ioccur-highlight-match-on-line (regexp)
-  "Highlight all occurences of REGEXP on precedent line."
-  (save-excursion
-    (forward-line -1)
-    (while (and (funcall ioccur-search-function regexp (point-at-eol) t)
-                ;; If length of match is null exit loop.
-                ;; e.g when searching "^".
-                (> (- (match-end 0) (match-beginning 0)) 0))
-      (put-text-property (match-beginning 0) (point)
-                         'face 'ioccur-regexp-face))))
-
-(defun ioccur-print-line (line nline regexp)
+(defun ioccur-print-line (line nline)
   "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let ((lineno     (int-to-string (1+ nline)))
@@ -310,9 +299,7 @@ Special commands:
       (insert " " (propertize
                    lineno 'face 'ioccur-num-line-face
                    'help-echo line)
-              ":" trunc-line "\n")
-      (when ioccur-highlight-match-p
-        (ioccur-highlight-match-on-line regexp)))))
+              ":" trunc-line "\n"))))
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
   "Remove indentation and truncate LINE of num COLUMNS.
@@ -779,7 +766,9 @@ M-p/n or tab/S-tab History."))
                     (propertize
                      (format " in %s" ioccur-current-buffer)
                      'face 'underline) "\n\n")
-            (ioccur-color-current-line)))))
+            (ioccur-color-current-line)
+            (when ioccur-highlight-match-p
+              (ioccur-highlight-match (point) regexp))))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."
@@ -949,6 +938,18 @@ of matched line in `ioccur-current-buffer'."
             (make-overlay (point-at-bol) (1+ (point-at-eol)))))
   (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
+(defun ioccur-highlight-match (beg regexp)
+  "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
+  (save-excursion
+    (goto-char beg)
+    (while (and (funcall ioccur-search-function regexp nil t)
+                (not (eobp))
+                ;; If length of match is null exit loop.
+                ;; e.g when searching "^".
+                (> (- (match-end 0) (match-beginning 0)) 0))
+      (put-text-property (match-beginning 0) (point)
+                         'face 'ioccur-regexp-face))))
+            
 
 (provide 'ioccur)
 

commit 7a716ec39af55947d4c9c75ee779ff26f81174cd
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Aug 27 08:42:05 2010 +0200

    Highlight regexp line by line instead of reparsing buffer.
    
    (ioccur-highlight-match-on-line) Replace ioccur-highlight-match
    (ioccur-print-line) new arg regexp, highlight regexp from here now.
    (ioccur-print-results) Pass regexp arg to *-print-line.

diff --git a/ioccur.el b/ioccur.el
index 3748983..d9121ad 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -287,10 +287,21 @@ Special commands:
          for count from 0
          when (funcall ioccur-search-function regexp (point-at-eol) t)
          do (ioccur-print-line
-             (buffer-substring (point-at-bol) (point-at-eol)) count)
+             (buffer-substring (point-at-bol) (point-at-eol)) count regexp)
          do (forward-line 1)))))
 
-(defun ioccur-print-line (line nline)
+(defun ioccur-highlight-match-on-line (regexp)
+  "Highlight all occurences of REGEXP on precedent line."
+  (save-excursion
+    (forward-line -1)
+    (while (and (funcall ioccur-search-function regexp (point-at-eol) t)
+                ;; If length of match is null exit loop.
+                ;; e.g when searching "^".
+                (> (- (match-end 0) (match-beginning 0)) 0))
+      (put-text-property (match-beginning 0) (point)
+                         'face 'ioccur-regexp-face))))
+
+(defun ioccur-print-line (line nline regexp)
   "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let ((lineno     (int-to-string (1+ nline)))
@@ -299,7 +310,9 @@ Special commands:
       (insert " " (propertize
                    lineno 'face 'ioccur-num-line-face
                    'help-echo line)
-              ":" trunc-line "\n"))))
+              ":" trunc-line "\n")
+      (when ioccur-highlight-match-p
+        (ioccur-highlight-match-on-line regexp)))))
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
   "Remove indentation and truncate LINE of num COLUMNS.
@@ -766,9 +779,7 @@ M-p/n or tab/S-tab History."))
                     (propertize
                      (format " in %s" ioccur-current-buffer)
                      'face 'underline) "\n\n")
-            (ioccur-color-current-line)
-            (when ioccur-highlight-match-p
-              (ioccur-highlight-match (point) regexp))))))
+            (ioccur-color-current-line)))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."
@@ -938,18 +949,6 @@ of matched line in `ioccur-current-buffer'."
             (make-overlay (point-at-bol) (1+ (point-at-eol)))))
   (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
-(defun ioccur-highlight-match (beg regexp)
-  "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
-  (save-excursion
-    (goto-char beg)
-    (while (and (funcall ioccur-search-function regexp nil t)
-                (not (eobp))
-                ;; If length of match is null exit loop.
-                ;; e.g when searching "^".
-                (> (- (match-end 0) (match-beginning 0)) 0))
-      (put-text-property (match-beginning 0) (point)
-                         'face 'ioccur-regexp-face))))
-            
 
 (provide 'ioccur)
 

commit 9b5f290c71ce25eb9f7566bf119446926da9e971
Merge: b5678a9 7df0028
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Aug 26 22:52:07 2010 +0200

    merge branchs.


commit 7df0028f2a3a291241c31a2ecd76b5546e392d4a
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Aug 26 22:21:29 2010 +0200

    (ioccur-jump) Recenter when jumping.

diff --git a/ioccur.el b/ioccur.el
index 7339a38..3748983 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -471,7 +471,7 @@ Move point to first occurence of `ioccur-pattern'."
                 (string= line "Ioccur"))
       (pop-to-buffer ioccur-current-buffer t)
       (show-all) ; For org and outline enabled buffers.
-      (ioccur-goto-line pos)
+      (ioccur-goto-line pos) (recenter)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-pattern'.
       (when (funcall ioccur-search-function

commit b5678a91d0eb5bfc3bf68fd812cdb15da551d55d
Merge: 986e9eb 523e59e
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Aug 26 15:24:44 2010 +0200

    Merge from dev branch.


commit 986e9ebe95cdf835382db3810fe33ab4f0e90e72
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 12:27:42 2010 +0200

    Fix split-window in -nw by binding it to C-s instead of C-|.

diff --git a/ioccur.el b/ioccur.el
index 4f39bbd..7339a38 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -664,7 +664,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (ioccur-scroll-other-window-down) t)
                  ((?\C-t ?\M-v prior)           ; Scroll up.
                   (ioccur-scroll-other-window-up) t)
-                 (?\C-|                         ; Toggle split window.
+                 (?\C-s                         ; Toggle split window.
                   (ioccur-split-window) t)
                  ((?\C-: ?\C-l)                 ; Toggle regexp/litteral 
search.
                   (if (eq ioccur-search-function 're-search-forward)
@@ -739,7 +739,7 @@ C-k                Kill current input.\n
 M-k/C-x            Kill current input as sexp.\n
 C-w                Yank stuff at point.\n
 C-g                Quit and restore buffer.\n
-C-|                Toggle split window.\n
+C-s                Toggle split window.\n
 C-:/l              Toggle regexp/litteral search.\n
 C-down or C-u      Follow in other buffer.\n
 C-up/d or C-d      Follow in other buffer.\n
@@ -801,7 +801,7 @@ C-k            Kill current input.
 M-k             Kill current input as sexp.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
-C-|            Toggle split window.
+C-s            Toggle split window.
 C-:            Toggle regexp/litteral search.
 C-down         Follow in other buffer.
 C-up           Follow in other buffer.

commit 69e0d4792487178c0dc4468890c3b20fae882810
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 09:10:46 2010 +0200

    (ioccur-highlight-match-p) New user variable to allow enabling/disabling 
highlight in `ioccur-buffer'.

diff --git a/ioccur.el b/ioccur.el
index 2a98285..4f39bbd 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -129,6 +129,11 @@ Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'symbol)
 
+(defcustom ioccur-highlight-match-p t
+  "*Highlight matchs in `ioccur-buffer' when non--nil."
+  :group 'ioccur
+  :type 'boolean)
+
 (defvar ioccur-read-char-or-event-skip-read-key nil
   "*Force not using `read-key' even if bounded.
 You should not have to set this yourself.
@@ -762,7 +767,8 @@ M-p/n or tab/S-tab History."))
                      (format " in %s" ioccur-current-buffer)
                      'face 'underline) "\n\n")
             (ioccur-color-current-line)
-            (ioccur-highlight-match (point) regexp)))))
+            (when ioccur-highlight-match-p
+              (ioccur-highlight-match (point) regexp))))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."

commit 79474c4c861924f0be700ab9380c0e68933d6738
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 08:57:12 2010 +0200

    (ioccur-highlight-match) Fix infinite loop when match is zero length.

diff --git a/ioccur.el b/ioccur.el
index 8e801aa..2a98285 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -936,7 +936,11 @@ of matched line in `ioccur-current-buffer'."
   "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
   (save-excursion
     (goto-char beg)
-    (while (funcall ioccur-search-function regexp nil t)
+    (while (and (funcall ioccur-search-function regexp nil t)
+                (not (eobp))
+                ;; If length of match is null exit loop.
+                ;; e.g when searching "^".
+                (> (- (match-end 0) (match-beginning 0)) 0))
       (put-text-property (match-beginning 0) (point)
                          'face 'ioccur-regexp-face))))
             

commit de1eb5f4bc31eda9c31f18acde32c7b010d0c864
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 07:52:17 2010 +0200

    (ioccur) add comment, remove unused code at end.

diff --git a/ioccur.el b/ioccur.el
index 8831dd6..8e801aa 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -871,6 +871,9 @@ for commands provided in the `ioccur-buffer'."
                      (delete-overlay ioccur-match-overlay))
                    (delete-other-windows) (goto-char curpos)
                    (ioccur-send-message)
+                   ;; If `ioccur-message' is non--nil, thats mean we exit
+                   ;; with a specific action other than `C-g',
+                   ;; so we save history.
                    (when ioccur-message (ioccur-save-history)))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
                    (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
@@ -882,9 +885,7 @@ for commands provided in the `ioccur-buffer'."
             (setq ioccur-count-occurences 0)
             (setq ioccur-quit-flag nil)
             (setq ioccur-message nil)
-            (setq ioccur-search-function ioccur-default-search-function)
-            (with-current-buffer ioccur-current-buffer
-              (setq mark-active nil)))))))
+            (setq ioccur-search-function ioccur-default-search-function))))))
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."

commit 411b188c98e6fc38ea83fd281fc9575ab1f7fde3
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 07:44:32 2010 +0200

    (ioccur-highlight-match) use ioccur-search-function instead of 
re-search-forward.

diff --git a/ioccur.el b/ioccur.el
index 2a18463..8831dd6 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -935,7 +935,7 @@ of matched line in `ioccur-current-buffer'."
   "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
   (save-excursion
     (goto-char beg)
-    (while (re-search-forward regexp nil t)
+    (while (funcall ioccur-search-function regexp nil t)
       (put-text-property (match-beginning 0) (point)
                          'face 'ioccur-regexp-face))))
             

commit 7827e741157314d572ce465c44f9b565bf5e5c32
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Aug 25 07:34:55 2010 +0200

    (ioccur-print-buffer) Highlight all matchs in ioccur-buffer.
    (ioccur-highlight-match) new.

diff --git a/ioccur.el b/ioccur.el
index 8a101a9..2a18463 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -761,7 +761,8 @@ M-p/n or tab/S-tab History."))
                     (propertize
                      (format " in %s" ioccur-current-buffer)
                      'face 'underline) "\n\n")
-            (ioccur-color-current-line)))))
+            (ioccur-color-current-line)
+            (ioccur-highlight-match (point) regexp)))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."
@@ -930,6 +931,14 @@ of matched line in `ioccur-current-buffer'."
             (make-overlay (point-at-bol) (1+ (point-at-eol)))))
   (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
+(defun ioccur-highlight-match (beg regexp)
+  "Highlight all occurences of REGEXP from BEG to end of `ioccur-buffer'."
+  (save-excursion
+    (goto-char beg)
+    (while (re-search-forward regexp nil t)
+      (put-text-property (match-beginning 0) (point)
+                         'face 'ioccur-regexp-face))))
+            
 
 (provide 'ioccur)
 

commit 83bb8625c67026b51fe45d2a04a1e24eb15ecdce
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 23 12:58:26 2010 +0200

    (ioccur) Remove now unused save-restriction.

diff --git a/ioccur.el b/ioccur.el
index b8c0231..8a101a9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -821,70 +821,69 @@ Special NOTE for terms:
 When you quit incremental search with RET, see `ioccur-mode'
 for commands provided in the `ioccur-buffer'."
   (interactive "P")
-  (save-restriction
-    (setq ioccur-exit-and-quit-p nil)
-    (setq ioccur-success nil)
-    (setq ioccur-current-buffer (buffer-name (current-buffer)))
-    (message "Fontifying buffer...Please wait it could be long.")
-    (jit-lock-fontify-now) (message nil)
-    (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
-    (if (and (not initial-input)
-             (get-buffer ioccur-buffer)
-             (not (get-buffer-window ioccur-buffer)))
-        ;; An hidden `ioccur-buffer' exists jump to it.
-        (pop-to-buffer ioccur-buffer t)
-        ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
-        (let* ((init-str (if initial-input
-                             (if (stringp initial-input)
-                                 initial-input
-                                 (thing-at-point 'symbol))
-                             ""))
-               (len      (length init-str))
-               (curpos   (point))
-               (cur-mode (with-current-buffer ioccur-current-buffer
-                           (prog1
-                               major-mode
-                             ;; If current `major-mode' is wdired
-                             ;; Turn it off.
-                             (when (eq major-mode 'wdired-mode)
-                               (wdired-change-to-dired-mode)))))
-               str-no-prop)
-          (set-text-properties 0 len nil init-str)
-          (setq str-no-prop init-str)
-          (pop-to-buffer (get-buffer-create ioccur-buffer) t)
-          (ioccur-mode)
-          (unwind-protect
-               ;; Start incremental search.
-               (progn
-                 (ioccur-start-timer)
-                 (ioccur-read-search-input str-no-prop curpos))
-            ;; At this point incremental search loop is exited.
-            (progn
-              (ioccur-cancel-search)
-              (kill-local-variable 'mode-line-format)
-              (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
-                (setq ioccur-quit-flag t))
-              (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
-                     (kill-buffer ioccur-buffer)
-                     (switch-to-buffer ioccur-current-buffer)
-                     (when ioccur-match-overlay
-                       (delete-overlay ioccur-match-overlay))
-                     (delete-other-windows) (goto-char curpos)
-                     (ioccur-send-message)
-                     (when ioccur-message (ioccur-save-history)))
-                    (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
-                     (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
-                     (ioccur-send-message) (ioccur-save-history))
-                    (t                 ; Jump keeping `ioccur-buffer'.
-                     (ioccur-jump) (other-window 1) (ioccur-save-history)))
-              ;; Maybe reenable `wdired-mode'.
-              (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
-              (setq ioccur-count-occurences 0)
-              (setq ioccur-quit-flag nil)
-              (setq ioccur-message nil)
-              (setq ioccur-search-function ioccur-default-search-function)
-              (with-current-buffer ioccur-current-buffer
-                (setq mark-active nil))))))))
+  (setq ioccur-exit-and-quit-p nil)
+  (setq ioccur-success nil)
+  (setq ioccur-current-buffer (buffer-name (current-buffer)))
+  (message "Fontifying buffer...Please wait it could be long.")
+  (jit-lock-fontify-now) (message nil)
+  (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
+  (if (and (not initial-input)
+           (get-buffer ioccur-buffer)
+           (not (get-buffer-window ioccur-buffer)))
+      ;; An hidden `ioccur-buffer' exists jump to it.
+      (pop-to-buffer ioccur-buffer t)
+      ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
+      (let* ((init-str (if initial-input
+                           (if (stringp initial-input)
+                               initial-input
+                               (thing-at-point 'symbol))
+                           ""))
+             (len      (length init-str))
+             (curpos   (point))
+             (cur-mode (with-current-buffer ioccur-current-buffer
+                         (prog1
+                             major-mode
+                           ;; If current `major-mode' is wdired
+                           ;; Turn it off.
+                           (when (eq major-mode 'wdired-mode)
+                             (wdired-change-to-dired-mode)))))
+             str-no-prop)
+        (set-text-properties 0 len nil init-str)
+        (setq str-no-prop init-str)
+        (pop-to-buffer (get-buffer-create ioccur-buffer) t)
+        (ioccur-mode)
+        (unwind-protect
+             ;; Start incremental search.
+             (progn
+               (ioccur-start-timer)
+               (ioccur-read-search-input str-no-prop curpos))
+          ;; At this point incremental search loop is exited.
+          (progn
+            (ioccur-cancel-search)
+            (kill-local-variable 'mode-line-format)
+            (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
+              (setq ioccur-quit-flag t))
+            (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
+                   (kill-buffer ioccur-buffer)
+                   (switch-to-buffer ioccur-current-buffer)
+                   (when ioccur-match-overlay
+                     (delete-overlay ioccur-match-overlay))
+                   (delete-other-windows) (goto-char curpos)
+                   (ioccur-send-message)
+                   (when ioccur-message (ioccur-save-history)))
+                  (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
+                   (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
+                   (ioccur-send-message) (ioccur-save-history))
+                  (t                   ; Jump keeping `ioccur-buffer'.
+                   (ioccur-jump) (other-window 1) (ioccur-save-history)))
+            ;; Maybe reenable `wdired-mode'.
+            (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
+            (setq ioccur-count-occurences 0)
+            (setq ioccur-quit-flag nil)
+            (setq ioccur-message nil)
+            (setq ioccur-search-function ioccur-default-search-function)
+            (with-current-buffer ioccur-current-buffer
+              (setq mark-active nil)))))))
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."

commit f6d1f9d7c6656c8fce831f15d7195e22170ca3ca
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 22 22:50:56 2010 +0200

    (ioccur):Regression remove narrowing code that cause problems elsewhere.

diff --git a/ioccur.el b/ioccur.el
index 0fe7624..b8c0231 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -826,13 +826,7 @@ for commands provided in the `ioccur-buffer'."
     (setq ioccur-success nil)
     (setq ioccur-current-buffer (buffer-name (current-buffer)))
     (message "Fontifying buffer...Please wait it could be long.")
-    (if (region-active-p)
-        (let ((beg (region-beginning))
-              (end (region-end)))
-          (narrow-to-region beg end)
-          (jit-lock-fontify-now beg end))
-        (jit-lock-fontify-now))
-    (message nil) ; Remove pecedent message.
+    (jit-lock-fontify-now) (message nil)
     (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
     (if (and (not initial-input)
              (get-buffer ioccur-buffer)

commit 0f937335777b2e97ddf03439ce2479ae26056966
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 22 11:29:19 2010 +0200

    (ioccur, ioccur-find-buffer-matching1) Remove extra args beg end, don't 
call interactively ioccur in *-restart.

diff --git a/ioccur.el b/ioccur.el
index bc369ce..0fe7624 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -376,7 +376,7 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
              (unwind-protect
                   (progn
                     (switch-to-buffer buf)
-                    (ioccur regexp (point-min) (point-max))
+                    (ioccur regexp)
                     ;; Exit if we jump to this `ioccur-current-buffer',
                     ;; otherwise, if C-g is hitten,
                     ;; go back to buffer completion list.
@@ -417,7 +417,7 @@ See `ioccur-find-buffer-matching1'."
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
   (when (and (eq major-mode 'ioccur-mode) (eq (count-windows) 2))
-    (other-window 1) (call-interactively 'ioccur)))
+    (other-window 1) (ioccur)))
 
 ;;;###autoload
 (defun ioccur-quit ()
@@ -777,7 +777,7 @@ M-p/n or tab/S-tab History."))
   (message ioccur-message))
 
 ;;;###autoload
-(defun ioccur (initial-input beg end)
+(defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.
 With a prefix arg search symbol at point (INITIAL-INPUT).
 
@@ -820,17 +820,19 @@ Special NOTE for terms:
  
 When you quit incremental search with RET, see `ioccur-mode'
 for commands provided in the `ioccur-buffer'."
-  (interactive "P\nr")
+  (interactive "P")
   (save-restriction
     (setq ioccur-exit-and-quit-p nil)
     (setq ioccur-success nil)
     (setq ioccur-current-buffer (buffer-name (current-buffer)))
-    (if (region-active-p)
-        (narrow-to-region beg end)
-        (setq beg (point-min) end (point-max)))
     (message "Fontifying buffer...Please wait it could be long.")
-    (jit-lock-fontify-now beg end)
-    (message nil)
+    (if (region-active-p)
+        (let ((beg (region-beginning))
+              (end (region-end)))
+          (narrow-to-region beg end)
+          (jit-lock-fontify-now beg end))
+        (jit-lock-fontify-now))
+    (message nil) ; Remove pecedent message.
     (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
     (if (and (not initial-input)
              (get-buffer ioccur-buffer)

commit 1a8b44dd46197c7e760a61eafe19389e42ebd281
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 22 08:34:55 2010 +0200

    (ioccur-find-buffer-matching1) call ioccur with extra args.
    (ioccur-restart) call ioccur interactively.

diff --git a/ioccur.el b/ioccur.el
index 157811d..bc369ce 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -376,7 +376,7 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
              (unwind-protect
                   (progn
                     (switch-to-buffer buf)
-                    (ioccur regexp)
+                    (ioccur regexp (point-min) (point-max))
                     ;; Exit if we jump to this `ioccur-current-buffer',
                     ;; otherwise, if C-g is hitten,
                     ;; go back to buffer completion list.
@@ -417,7 +417,7 @@ See `ioccur-find-buffer-matching1'."
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
   (when (and (eq major-mode 'ioccur-mode) (eq (count-windows) 2))
-    (other-window 1) (ioccur)))
+    (other-window 1) (call-interactively 'ioccur)))
 
 ;;;###autoload
 (defun ioccur-quit ()

commit 09b998e2ad926852eee3a3d74f9d539a67555dba
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 22 08:20:28 2010 +0200

    (ioccur) When region is active, narrow it and search only there, 
fontification is made only there also.

diff --git a/ioccur.el b/ioccur.el
index 59700b7..157811d 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -777,7 +777,7 @@ M-p/n or tab/S-tab History."))
   (message ioccur-message))
 
 ;;;###autoload
-(defun ioccur (&optional initial-input)
+(defun ioccur (initial-input beg end)
   "Incremental search of lines in current buffer matching input.
 With a prefix arg search symbol at point (INITIAL-INPUT).
 
@@ -798,7 +798,9 @@ C-|            Toggle split window.
 C-:            Toggle regexp/litteral search.
 C-down         Follow in other buffer.
 C-up           Follow in other buffer.
-M-p/n          Precedent and next `ioccur-history' element:
+M-p/n          Precedent and next `ioccur-history' element.
+
+Unlike minibuffer history, ioccur history is a ring (no end):
 
 M-p ,-->A B C D E F G H I---,
     |                       |
@@ -808,6 +810,8 @@ M-n ,-->I H G F E D C B A---,
     |                       |
     `---A B C D E F G H I<--'
 
+If a region is active, search only in this region.
+
 Special NOTE for terms:
 =======================
   tab/S-tab are bound to history.
@@ -816,68 +820,75 @@ Special NOTE for terms:
  
 When you quit incremental search with RET, see `ioccur-mode'
 for commands provided in the `ioccur-buffer'."
-  (interactive "P")
-  (setq ioccur-exit-and-quit-p nil)
-  (setq ioccur-success nil)
-  (setq ioccur-current-buffer (buffer-name (current-buffer)))
-  (message "Fontifying buffer...Please wait it could be long.")
-  (jit-lock-fontify-now) (message nil)
-  (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
-  (if (and (not initial-input)
-           (get-buffer ioccur-buffer)
-           (not (get-buffer-window ioccur-buffer)))
-      ;; An hidden `ioccur-buffer' exists jump to it.
-      (pop-to-buffer ioccur-buffer t)
-      ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
-      (let* ((init-str (if initial-input
-                           (if (stringp initial-input)
-                               initial-input
-                               (thing-at-point 'symbol))
-                           ""))
-             (len      (length init-str))
-             (curpos   (point))
-             (cur-mode (with-current-buffer ioccur-current-buffer
-                         (prog1
-                             major-mode
-                           ;; If current `major-mode' is wdired
-                           ;; Turn it off.
-                           (when (eq major-mode 'wdired-mode)
-                             (wdired-change-to-dired-mode)))))
-             str-no-prop)
-        (set-text-properties 0 len nil init-str)
-        (setq str-no-prop init-str)
-        (pop-to-buffer (get-buffer-create ioccur-buffer) t)
-        (ioccur-mode)
-        (unwind-protect
-             ;; Start incremental search.
-             (progn
-               (ioccur-start-timer)
-               (ioccur-read-search-input str-no-prop curpos))
-          ;; At this point incremental search loop is exited.
-          (progn
-            (ioccur-cancel-search)
-            (kill-local-variable 'mode-line-format)
-            (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
-              (setq ioccur-quit-flag t))
-            (cond (ioccur-quit-flag       ; C-g hit or empty `ioccur-buffer'.
-                   (kill-buffer ioccur-buffer)
-                   (switch-to-buffer ioccur-current-buffer)
-                   (when ioccur-match-overlay
-                     (delete-overlay ioccur-match-overlay))
-                   (delete-other-windows) (goto-char curpos)
-                   (ioccur-send-message)
-                   (when ioccur-message (ioccur-save-history)))
-                  (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
-                   (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
-                   (ioccur-send-message) (ioccur-save-history))
-                  (t                      ; Jump keeping `ioccur-buffer'.
-                   (ioccur-jump) (other-window 1) (ioccur-save-history)))
-            ;; Maybe reenable `wdired-mode'.
-            (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
-            (setq ioccur-count-occurences 0)
-            (setq ioccur-quit-flag nil)
-            (setq ioccur-message nil)
-            (setq ioccur-search-function ioccur-default-search-function))))))
+  (interactive "P\nr")
+  (save-restriction
+    (setq ioccur-exit-and-quit-p nil)
+    (setq ioccur-success nil)
+    (setq ioccur-current-buffer (buffer-name (current-buffer)))
+    (if (region-active-p)
+        (narrow-to-region beg end)
+        (setq beg (point-min) end (point-max)))
+    (message "Fontifying buffer...Please wait it could be long.")
+    (jit-lock-fontify-now beg end)
+    (message nil)
+    (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
+    (if (and (not initial-input)
+             (get-buffer ioccur-buffer)
+             (not (get-buffer-window ioccur-buffer)))
+        ;; An hidden `ioccur-buffer' exists jump to it.
+        (pop-to-buffer ioccur-buffer t)
+        ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
+        (let* ((init-str (if initial-input
+                             (if (stringp initial-input)
+                                 initial-input
+                                 (thing-at-point 'symbol))
+                             ""))
+               (len      (length init-str))
+               (curpos   (point))
+               (cur-mode (with-current-buffer ioccur-current-buffer
+                           (prog1
+                               major-mode
+                             ;; If current `major-mode' is wdired
+                             ;; Turn it off.
+                             (when (eq major-mode 'wdired-mode)
+                               (wdired-change-to-dired-mode)))))
+               str-no-prop)
+          (set-text-properties 0 len nil init-str)
+          (setq str-no-prop init-str)
+          (pop-to-buffer (get-buffer-create ioccur-buffer) t)
+          (ioccur-mode)
+          (unwind-protect
+               ;; Start incremental search.
+               (progn
+                 (ioccur-start-timer)
+                 (ioccur-read-search-input str-no-prop curpos))
+            ;; At this point incremental search loop is exited.
+            (progn
+              (ioccur-cancel-search)
+              (kill-local-variable 'mode-line-format)
+              (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
+                (setq ioccur-quit-flag t))
+              (cond (ioccur-quit-flag ; C-g hit or empty `ioccur-buffer'.
+                     (kill-buffer ioccur-buffer)
+                     (switch-to-buffer ioccur-current-buffer)
+                     (when ioccur-match-overlay
+                       (delete-overlay ioccur-match-overlay))
+                     (delete-other-windows) (goto-char curpos)
+                     (ioccur-send-message)
+                     (when ioccur-message (ioccur-save-history)))
+                    (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
+                     (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
+                     (ioccur-send-message) (ioccur-save-history))
+                    (t                 ; Jump keeping `ioccur-buffer'.
+                     (ioccur-jump) (other-window 1) (ioccur-save-history)))
+              ;; Maybe reenable `wdired-mode'.
+              (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
+              (setq ioccur-count-occurences 0)
+              (setq ioccur-quit-flag nil)
+              (setq ioccur-message nil)
+              (setq ioccur-search-function ioccur-default-search-function)
+              (with-current-buffer ioccur-current-buffer
+                (setq mark-active nil))))))))
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."

commit c68ab6ab1894e06033c13f83c3ec1fadc10ebb8a
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 21 17:26:16 2010 +0200

    (ioccur-read-char-or-event-skip-read-key) is now a defvar as bug#6881 and 
bug#6883 have been fixed (Thanks Leo and Stefan).

diff --git a/ioccur.el b/ioccur.el
index d41b1ff..59700b7 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -129,10 +129,10 @@ Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'symbol)
 
-(defcustom ioccur-read-char-or-event-skip-read-key nil
-  "*Force not using `read-key' even if bounded."
-    :group 'ioccur
-    :type 'boolean)
+(defvar ioccur-read-char-or-event-skip-read-key nil
+  "*Force not using `read-key' even if bounded.
+You should not have to set this yourself.
+Set it to non--nil if menu disapear or if keys are echoing in minibuffer.")
 
 ;;; Faces.
 (defface ioccur-overlay-face
@@ -661,14 +661,14 @@ START-POINT is the point where we start searching in 
buffer."
                   (ioccur-scroll-other-window-up) t)
                  (?\C-|                         ; Toggle split window.
                   (ioccur-split-window) t)
-                 ((?\C-: ?\C-l)                         ; Toggle 
regexp/litteral search.
+                 ((?\C-: ?\C-l)                 ; Toggle regexp/litteral 
search.
                   (if (eq ioccur-search-function 're-search-forward)
                       (setq ioccur-search-function 'search-forward)
                       (setq ioccur-search-function 're-search-forward)) t)
                  (?\C-k                         ; Kill input.
                   (start-timer)
                   (kill ioccur-pattern) t)
-                 ((?\M-k ?\C-x)                         ; Kill input as sexp.
+                 ((?\M-k ?\C-x)                 ; Kill input as sexp.
                   (start-timer)
                   (let ((sexp (prin1-to-string ioccur-pattern)))
                     (kill sexp)

commit a7446d64a2e68ef1142a15cc38eef437118dfd1e
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Aug 21 16:52:15 2010 +0200

    (ioccur-read-search-input) Remove old-yank-point no more needed.

diff --git a/ioccur.el b/ioccur.el
index 78be48d..d41b1ff 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -557,7 +557,6 @@ START-POINT is the point where we start searching in 
buffer."
          (it-next        nil)
          (cur-hist-elm   (car ioccur-history))
          (start-hist     nil) ; Flag to notify if cycling history started.
-         (old-yank-point start-point)
          yank-point)
     (unless (string= initial-input "")
       (loop for char across initial-input do (push char tmp-list)))
@@ -621,8 +620,8 @@ START-POINT is the point where we start searching in 
buffer."
            ;;
            (kill (str)
              (with-current-buffer ioccur-current-buffer
-               (goto-char old-yank-point)
-               (setq yank-point old-yank-point))
+               (goto-char start-point)
+               (setq yank-point start-point))
              (kill-new str) (setq tmp-list ())))
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
@@ -647,8 +646,8 @@ START-POINT is the point where we start searching in 
buffer."
                  (?\d                           ; Delete backward with DEL.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
-                    (goto-char old-yank-point)
-                    (setq yank-point old-yank-point))
+                    (goto-char start-point)
+                    (setq yank-point start-point))
                   (pop tmp-list) t)
                  (?\C-g                         ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
@@ -683,7 +682,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     ;; Start to initial point if C-w have never been hit.
-                    (unless yank-point (setq yank-point old-yank-point))
+                    (unless yank-point (setq yank-point start-point))
                     ;; After a search `ioccur-print-results' have put point
                     ;; to point-max, so reset position.
                     (when yank-point (goto-char yank-point))

commit 90b8b657ea6de6b97346a481c73291a2ff35a319
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Aug 20 12:09:36 2010 +0200

    Save history when killing as sexp.

diff --git a/ioccur.el b/ioccur.el
index 2e46b97..78be48d 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -866,7 +866,8 @@ for commands provided in the `ioccur-buffer'."
                    (when ioccur-match-overlay
                      (delete-overlay ioccur-match-overlay))
                    (delete-other-windows) (goto-char curpos)
-                   (ioccur-send-message))
+                   (ioccur-send-message)
+                   (when ioccur-message (ioccur-save-history)))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
                    (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
                    (ioccur-send-message) (ioccur-save-history))

commit 2924aac3a39cac1180da11a39b7bc2a1c51d7641
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Aug 20 10:13:17 2010 +0200

    (ioccur-message) new internal variable.
    (ioccur-send-message) new: send message with value of ioccur-message.
    (ioccur-read-search-input) M-k send a message when killing as sexp.

diff --git a/ioccur.el b/ioccur.el
index a9cf74a..2e46b97 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -193,6 +193,8 @@ Use here one of `re-search-forward' or `search-forward'."
 (defvar ioccur-success nil)
 ;; Search function actually in use.
 (defvar ioccur-search-function ioccur-default-search-function)
+;; Message to send when ioccur exit
+(defvar ioccur-message nil)
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -669,8 +671,11 @@ START-POINT is the point where we start searching in 
buffer."
                   (kill ioccur-pattern) t)
                  ((?\M-k ?\C-x)                         ; Kill input as sexp.
                   (start-timer)
-                  (kill (prin1-to-string ioccur-pattern))
-                  (setq ioccur-quit-flag t) nil)
+                  (let ((sexp (prin1-to-string ioccur-pattern)))
+                    (kill sexp)
+                    (setq ioccur-quit-flag t)
+                    (setq ioccur-message (format "Killed: %s" sexp)))
+                  nil)
                  (?\C-y                         ; Yank from `kill-ring'.
                   (setq initial-input (car kill-ring))
                   (insert-initial-input) t)
@@ -768,6 +773,9 @@ M-p/n or tab/S-tab History."))
              (ioccur-print-buffer
               ioccur-pattern)))))
 
+(defun ioccur-send-message ()
+  "Send message defined in `ioccur-message'."
+  (message ioccur-message))
 
 ;;;###autoload
 (defun ioccur (&optional initial-input)
@@ -858,16 +866,17 @@ for commands provided in the `ioccur-buffer'."
                    (when ioccur-match-overlay
                      (delete-overlay ioccur-match-overlay))
                    (delete-other-windows) (goto-char curpos)
-                   (message nil))
+                   (ioccur-send-message))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
                    (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
-                   (message nil) (ioccur-save-history))
+                   (ioccur-send-message) (ioccur-save-history))
                   (t                      ; Jump keeping `ioccur-buffer'.
                    (ioccur-jump) (other-window 1) (ioccur-save-history)))
             ;; Maybe reenable `wdired-mode'.
             (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
             (setq ioccur-count-occurences 0)
             (setq ioccur-quit-flag nil)
+            (setq ioccur-message nil)
             (setq ioccur-search-function ioccur-default-search-function))))))
 
 (defun ioccur-save-history ()

commit 270a74d6ea95d93e4f993982fc935638c4abd321
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Aug 19 12:28:05 2010 +0200

    (ioccur-read-char-or-event-skip-read-key) new when non--nil always skip use 
of read-key.

diff --git a/ioccur.el b/ioccur.el
index 4e0c7ac..a9cf74a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -129,6 +129,11 @@ Use here one of `re-search-forward' or `search-forward'."
   :group 'ioccur
   :type 'symbol)
 
+(defcustom ioccur-read-char-or-event-skip-read-key nil
+  "*Force not using `read-key' even if bounded."
+    :group 'ioccur
+    :type 'boolean)
+
 ;;; Faces.
 (defface ioccur-overlay-face
     '((t (:background "Green4" :underline t)))
@@ -529,7 +534,8 @@ Move point to first occurence of `ioccur-pattern'."
 
 (defun ioccur-read-char-or-event (prompt)
   "Replace `read-key' when not available using PROMPT."
-  (if (fboundp 'read-key)
+  (if (and (fboundp 'read-key)
+           (not ioccur-read-char-or-event-skip-read-key))
       (read-key prompt)
       (let* ((chr (condition-case nil (read-char prompt) (error nil)))
              (evt (unless chr (read-event prompt))))
@@ -542,7 +548,8 @@ START-POINT is the point where we start searching in 
buffer."
   (let* ((prompt         (propertize ioccur-search-prompt
                                      'face 'minibuffer-prompt))
          (inhibit-quit   (or (eq system-type 'windows-nt)
-                             (not (fboundp 'read-key))))
+                             (not (fboundp 'read-key))
+                             ioccur-read-char-or-event-skip-read-key))
          (tmp-list       ())
          (it-prec        nil)
          (it-next        nil)

commit 227a3608cd89eefcb79453ffc646027bcbe791bd
Author: Orlando Hill <address@hidden>
Date:   Wed Aug 11 08:09:12 2010 +0800

    Customize args for compiling files and display the first compiler error
    
    Repurpose the unused custom variable 'coffee-args-compile' and the unused
    function 'coffee-command-full'. 'coffee-args-compile' now gives extra 
arguments
    to the 'coffee-command' when a file is compiled.
    
    'coffee-args-compile' defaults to just '-c' (the same behaviour as v0.3.0) 
and
    an example of using '--no-wrap' is added to the coffee-mode-hook example in 
the
    README.
    
    If compilation fails, the first compiler error is displayed in the message
    buffer.

diff --git a/README.md b/README.md
index d2d5117..095c9e9 100644
--- a/README.md
+++ b/README.md
@@ -202,6 +202,9 @@ Naturally. Example:
       ;; If you don't have js2-mode
       (setq coffee-js-mode 'javascript-mode)
 
+      ;; If you don't want your compiled files to be wrapped
+      (setq coffee-args-compile '("-c" "--no-wrap"))
+
       ;; *Messages* spam
       (setq coffee-debug-mode t)
 
@@ -267,10 +270,9 @@ Default: `'("-i")`
 
 ### coffee-args-compile
 
-The command line arguments to pass to `coffee-command' to get it
-toprint the compiled JavaScript.
+The command line arguments to pass to `coffee-command' when compiling a file.
 
-Default: `'("-s" "-p" "--no-wrap")`
+Default: `'("-c")`
 
 ### coffee-compiled-buffer-name
 
diff --git a/coffee-mode.el b/coffee-mode.el
index b72646c..eb69449 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -104,9 +104,8 @@ path."
   :type 'list
   :group 'coffee)
 
-(defcustom coffee-args-compile '("-s" "-p" "--no-wrap")
-  "The command line arguments to pass to `coffee-command' to get it to
-print the compiled JavaScript."
+(defcustom coffee-args-compile '("-c")
+  "The command line arguments to pass to `coffee-command' when compiling a 
file."
   :type 'list
   :group 'coffee)
 
@@ -160,11 +159,10 @@ print the compiled JavaScript."
 (defun coffee-compile-file ()
   "Compiles and saves the current file to disk. Doesn't open in a buffer.."
   (interactive)
-  (shell-command (concat coffee-command " -c " (buffer-file-name)))
-  (message "Compiled and saved %s"
-           (concat
-            (substring (buffer-file-name) 0 -6)
-            "js")))
+  (let ((compiler-output (shell-command-to-string (coffee-command-compile 
(buffer-file-name)))))
+    (if (string= compiler-output "")
+        (message "Compiled and saved %s" (concat (substring (buffer-file-name) 
0 -6) "js"))
+      (message (car (split-string compiler-output "[\n\r]+"))))))
 
 (defun coffee-compile-buffer ()
   "Compiles the current buffer and displays the JS in another buffer."
@@ -308,9 +306,9 @@ For detail, see `comment-dwim'."
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
-(defun coffee-command-full ()
-  "The full `coffee-command' complete with args."
-  (mapconcat 'identity (append (list coffee-command) coffee-args-compile) " "))
+(defun coffee-command-compile (file-name)
+  "The `coffee-command' with args to compile a file."
+  (mapconcat 'identity (append (list coffee-command) coffee-args-compile (list 
file-name)) " "))
 
 ;;
 ;; imenu support

commit cd06e4e6ebb60ac29cb90aaa31df89ba05d9a288
Author: Martin Kühl <address@hidden>
Date:   Sun Apr 4 05:40:35 2010 +0800

    Fix compiling `coffee-mode' without loading it.
    
    The variable `coffee-debug-mode' isn't defined at compile-time but used
    when expanding the `setd' macro.

diff --git a/coffee-mode.el b/coffee-mode.el
index ae27575..b72646c 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -127,7 +127,7 @@ print the compiled JavaScript."
 
 (defmacro setd (var val)
   "Like setq but optionally logs the variable's value using `coffee-debug'."
-  (if coffee-debug-mode
+  (if (and (boundp 'coffee-debug-mode) coffee-debug-mode)
       `(progn
          (coffee-debug "%s: %s" ',var ,val)
          (setq ,var ,val))

commit 6639c3606a6e420060601d94df30735925a6b596
Author: Martin Kühl <address@hidden>
Date:   Sat Mar 27 02:00:42 2010 +0800

    Silence byte-compiler warnings.

diff --git a/coffee-mode.el b/coffee-mode.el
index 5736ef3..ae27575 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -55,9 +55,12 @@
 
 ;;; Code:
 
+(require 'comint)
 (require 'easymenu)
 (require 'font-lock)
-(require 'cl)
+
+(eval-when-compile
+  (require 'cl))
 
 ;;
 ;; Customizable Variables
@@ -183,7 +186,7 @@ print the compiled JavaScript."
                        "-s" "-p" "--no-wrap")
   (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
   (funcall coffee-js-mode)
-  (beginning-of-buffer))
+  (goto-char (point-min)))
 
 (defun coffee-show-version ()
   "Prints the `coffee-mode' version."
@@ -354,7 +357,7 @@ For detail, see `comment-dwim'."
   (interactive)
 
   ;; This function is called within a `save-excursion' so we're safe.
-  (beginning-of-buffer)
+  (goto-char (point-min))
 
   (let ((index-alist '()) assign pos indent ns-name ns-indent)
     ;; Go through every assignment that includes -> or => on the same

commit 5afeb651e12b02a25139901008e943c012d083ec
Author: Orlando Hill <address@hidden>
Date:   Wed Aug 11 08:02:54 2010 +0800

    Fixed example hook in README to only compile .coffee files.

diff --git a/README.md b/README.md
index e680e21..d2d5117 100644
--- a/README.md
+++ b/README.md
@@ -211,10 +211,10 @@ Naturally. Example:
       ;; Riding edge.
       (setq coffee-command "~/dev/coffee"))
 
-      ;; Compile JS on every save, unless it's a Cakefile.
+      ;; Compile '.coffee' files on every save
       (add-hook 'after-save-hook
           '(lambda ()
-             (when (not (string= (buffer-name) "Cakefile"))
+             (when (string-match "\.coffee$" (buffer-name))
               (coffee-compile-file))))
 
     (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))

commit 2bb69bee23fa9613bcb9adcaf8b568f3d60dccc4
Author: Ryan Koopmans <address@hidden>
Date:   Sat Aug 14 07:21:00 2010 +0800

    Regex for "this" variable includes underscore.

diff --git a/coffee-mode.el b/coffee-mode.el
index 13456ba..5736ef3 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -228,7 +228,7 @@ print the compiled JavaScript."
 ;;
 
 ;; Instance variables (implicit this)
-(defvar coffee-this-regexp "@\\w*\\|this")
+(defvar coffee-this-regexp "@\\(\\w\\|_\\)*\\|this")
 
 ;; Prototype::access
 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| 
\\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")

commit 05b7ddb890da9f0fb01da455a561f8651b90114e
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Aug 16 08:35:28 2010 +0200

    Help improvement in mode-line and tooltip.

diff --git a/ioccur.el b/ioccur.el
index 7486f02..4e0c7ac 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -89,11 +89,11 @@
 
 (defcustom ioccur-mode-line-string
   (if (window-system)
-      " RET:Exit, C-j/left:Jump&quit, C-z/right:Jump, C-k/x:Kill(as sexp), \
-M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
+      " RET:Exit,C-g:Quit,C-j/left:Jump&quit,C-z/right:Jump,\
+C-k/x:Kill(as sexp),M-p/n:Hist,C/M-v:Scroll,C-down/up:Follow,C-w:Yank tap"
 
-      " RET:Exit, C-j:Jump&quit, C-z:Jump, C-k/x:Kill(as sexp), \
-S-/Tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
+      " RET:Exit,C-g:Quit,C-j:Jump&quit,C-z:Jump,C-k/x:Kill(as sexp),\
+S-/Tab:Hist,C-v/t:Scroll,C-d/u:Follow,C-w:Yank tap")
 
   "*Minimal documentation of `ioccur' commands displayed in mode-line.
 Set it to nil to remove doc in mode-line."
@@ -699,31 +699,35 @@ START-POINT is the point where we start searching in 
buffer."
 
 (defun ioccur-print-buffer (regexp)
   "Pretty Print results matching REGEXP in `ioccur-buffer'."
+  (unless (window-system) (setq tooltip-use-echo-area t) (tooltip-mode 1))
   (let* ((cur-method (if (eq ioccur-search-function 're-search-forward)
                          "Regexp" "Literal"))
-         (title (propertize
-                 (format "* Ioccur %s searching %s"
-                         cur-method (if (window-system)
-                                        "* (`C-:' to Toggle Method, Mouse over 
for help.)"
-                                        "* (`C-l' to Toggle Method.)"))
-                 'face 'ioccur-title-face
-                 'help-echo
-"C-n or <down>      next line.\n
-C-p or <up>         precedent line.\n
-C-v and M-v/C-t     scroll up and down.\n
-C-z or <right>      jump without quitting loop.\n
-C-j or <left>       jump and kill `ioccur-buffer'.\n
-RET                 exit keeping `ioccur-buffer'.\n
-DEL                 remove last character entered.\n
-C-k                 Kill current input.\n
-M-k/C-x             Kill current input as sexp.\n
-C-w                 Yank stuff at point.\n
-C-g                 quit and restore buffer.\n
-C-|                 Toggle split window.\n
-C-:/l               Toggle regexp/litteral search.\n
-C-down or C-u       Follow in other buffer.\n
-C-up/d or C-d       Follow in other buffer.\n
-M-p/n or tab/S-tab  History."))
+         (title      (propertize
+                      (format
+                       "* Ioccur %s searching %s"
+                       cur-method
+                       (if (window-system)
+                           "* (`C-:' to Toggle Method, Mouse over for help.)"
+                           "* (`C-l' to Toggle Method.)"))
+                      'face 'ioccur-title-face
+                      'help-echo
+                      "                  Ioccur map:\n
+C-n or <down>      Next line.\n
+C-p or <up>        Precedent line.\n
+C-v and M-v/C-t    Scroll up and down.\n
+C-z or <right>     Jump without quitting loop.\n
+C-j or <left>      Jump and kill `ioccur-buffer'.\n
+RET                Exit keeping `ioccur-buffer'.\n
+DEL                Remove last character entered.\n
+C-k                Kill current input.\n
+M-k/C-x            Kill current input as sexp.\n
+C-w                Yank stuff at point.\n
+C-g                Quit and restore buffer.\n
+C-|                Toggle split window.\n
+C-:/l              Toggle regexp/litteral search.\n
+C-down or C-u      Follow in other buffer.\n
+C-up/d or C-d      Follow in other buffer.\n
+M-p/n or tab/S-tab History."))
            wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))

commit 0bcf01ecf73e9be9e229ca3b4f91748963292492
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 15 23:30:28 2010 +0200

    Modify mode-line help, Fix compatibility with urxvt.

diff --git a/ioccur.el b/ioccur.el
index 9857b7b..7486f02 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -89,13 +89,13 @@
 
 (defcustom ioccur-mode-line-string
   (if (window-system)
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
-C-n/p:Next/Prec, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
+      " RET:Exit, C-j/left:Jump&quit, C-z/right:Jump, C-k/x:Kill(as sexp), \
+M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
 
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
-C-n/p:Next/Prec, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
+      " RET:Exit, C-j:Jump&quit, C-z:Jump, C-k/x:Kill(as sexp), \
+S-/Tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
 
-  "*Documentation of `ioccur' prompt displayed in mode-line.
+  "*Minimal documentation of `ioccur' commands displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
   :type  'string)
@@ -653,14 +653,14 @@ START-POINT is the point where we start searching in 
buffer."
                   (ioccur-scroll-other-window-up) t)
                  (?\C-|                         ; Toggle split window.
                   (ioccur-split-window) t)
-                 (?\C-:                         ; Toggle regexp/litteral 
search.
+                 ((?\C-: ?\C-l)                         ; Toggle 
regexp/litteral search.
                   (if (eq ioccur-search-function 're-search-forward)
                       (setq ioccur-search-function 'search-forward)
                       (setq ioccur-search-function 're-search-forward)) t)
                  (?\C-k                         ; Kill input.
                   (start-timer)
                   (kill ioccur-pattern) t)
-                 (?\M-k                         ; Kill input as sexp.
+                 ((?\M-k ?\C-x)                         ; Kill input as sexp.
                   (start-timer)
                   (kill (prin1-to-string ioccur-pattern))
                   (setq ioccur-quit-flag t) nil)
@@ -702,8 +702,10 @@ START-POINT is the point where we start searching in 
buffer."
   (let* ((cur-method (if (eq ioccur-search-function 're-search-forward)
                          "Regexp" "Literal"))
          (title (propertize
-                 (format "* Ioccur %s searching * (`C-:' to Toggle Method, 
Mouse over for help.)"
-                         cur-method)
+                 (format "* Ioccur %s searching %s"
+                         cur-method (if (window-system)
+                                        "* (`C-:' to Toggle Method, Mouse over 
for help.)"
+                                        "* (`C-l' to Toggle Method.)"))
                  'face 'ioccur-title-face
                  'help-echo
 "C-n or <down>      next line.\n
@@ -714,11 +716,11 @@ C-j or <left>       jump and kill `ioccur-buffer'.\n
 RET                 exit keeping `ioccur-buffer'.\n
 DEL                 remove last character entered.\n
 C-k                 Kill current input.\n
-M-k                 Kill current input as sexp.\n
+M-k/C-x             Kill current input as sexp.\n
 C-w                 Yank stuff at point.\n
 C-g                 quit and restore buffer.\n
 C-|                 Toggle split window.\n
-C-:                 Toggle regexp/litteral search.\n
+C-:/l               Toggle regexp/litteral search.\n
 C-down or C-u       Follow in other buffer.\n
 C-up/d or C-d       Follow in other buffer.\n
 M-p/n or tab/S-tab  History."))

commit 5a7a368e37e8cb044385f7a0bd93952588b614e0
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Aug 13 18:08:27 2010 +0200

    New M-k kill pattern as sexp.

diff --git a/ioccur.el b/ioccur.el
index 56e0bf8..9857b7b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -607,7 +607,14 @@ START-POINT is the point where we start searching in 
buffer."
            ;;
            (stop-timer ()
              (when ioccur-search-timer
-               (ioccur-cancel-search))))
+               (ioccur-cancel-search)))
+           ;; Kill pattern
+           ;;
+           (kill (str)
+             (with-current-buffer ioccur-current-buffer
+               (goto-char old-yank-point)
+               (setq yank-point old-yank-point))
+             (kill-new str) (setq tmp-list ())))
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-pattern))))
@@ -652,10 +659,11 @@ START-POINT is the point where we start searching in 
buffer."
                       (setq ioccur-search-function 're-search-forward)) t)
                  (?\C-k                         ; Kill input.
                   (start-timer)
-                  (with-current-buffer ioccur-current-buffer
-                    (goto-char old-yank-point)
-                    (setq yank-point old-yank-point))
-                  (kill-new ioccur-pattern) (setq tmp-list ()) t)
+                  (kill ioccur-pattern) t)
+                 (?\M-k                         ; Kill input as sexp.
+                  (start-timer)
+                  (kill (prin1-to-string ioccur-pattern))
+                  (setq ioccur-quit-flag t) nil)
                  (?\C-y                         ; Yank from `kill-ring'.
                   (setq initial-input (car kill-ring))
                   (insert-initial-input) t)
@@ -698,21 +706,22 @@ START-POINT is the point where we start searching in 
buffer."
                          cur-method)
                  'face 'ioccur-title-face
                  'help-echo
-"C-n or <down>  next line.\n
-C-p or <up>     precedent line.\n
-C-v and M-v     scroll up and down.\n
-C-z or <right>  jump without quitting loop.\n
-C-j or <left>   jump and kill `ioccur-buffer'.\n
-RET             exit keeping `ioccur-buffer'.\n
-DEL             remove last character entered.\n
-C-k             Kill current input.\n
-C-w             Yank stuff at point.\n
-C-g             quit and restore buffer.\n
-C-|             Toggle split window.\n
-C-:             Toggle regexp/litteral search.\n
-C-down          Follow in other buffer.\n
-C-up            Follow in other buffer.\n
-M-p/n           Precedent and next `ioccur-history' element."))
+"C-n or <down>      next line.\n
+C-p or <up>         precedent line.\n
+C-v and M-v/C-t     scroll up and down.\n
+C-z or <right>      jump without quitting loop.\n
+C-j or <left>       jump and kill `ioccur-buffer'.\n
+RET                 exit keeping `ioccur-buffer'.\n
+DEL                 remove last character entered.\n
+C-k                 Kill current input.\n
+M-k                 Kill current input as sexp.\n
+C-w                 Yank stuff at point.\n
+C-g                 quit and restore buffer.\n
+C-|                 Toggle split window.\n
+C-:                 Toggle regexp/litteral search.\n
+C-down or C-u       Follow in other buffer.\n
+C-up/d or C-d       Follow in other buffer.\n
+M-p/n or tab/S-tab  History."))
            wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
@@ -762,6 +771,7 @@ C-j or <left>  jump and kill `ioccur-buffer'.
 RET            exit keeping `ioccur-buffer'.
 DEL            remove last character entered.
 C-k            Kill current input.
+M-k             Kill current input as sexp.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
 C-|            Toggle split window.

commit d40a1eca94a7e7c3d82cb03c09f68e674f25ed4b
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Aug 10 21:32:55 2010 +0200

    Rename ioccur-search-pattern to ioccur-pattern.

diff --git a/ioccur.el b/ioccur.el
index 5f82a2a..56e0bf8 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -163,7 +163,7 @@ Use here one of `re-search-forward' or `search-forward'."
 
 ;;; Internal variables.
 ;; String entered in prompt.
-(defvar ioccur-search-pattern "")
+(defvar ioccur-pattern "")
 ;; The ioccur timer.
 (defvar ioccur-search-timer nil)
 ;; Signal C-g hit.
@@ -450,7 +450,7 @@ Goto NUMLINE."
 
 (defun ioccur-jump ()
   "Jump to line in other buffer and put an overlay on it.
-Move point to first occurence of `ioccur-search-pattern'."
+Move point to first occurence of `ioccur-pattern'."
   (let* ((line           (buffer-substring (point-at-bol) (point-at-eol)))
          (pos            (string-to-number line))
          (back-search-fn (if (eq ioccur-search-function 're-search-forward)
@@ -461,10 +461,10 @@ Move point to first occurence of `ioccur-search-pattern'."
       (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos)
       ;; Go to beginning of first occurence in this line
-      ;; of what match `ioccur-search-pattern'.
+      ;; of what match `ioccur-pattern'.
       (when (funcall ioccur-search-function
-                     ioccur-search-pattern (point-at-eol) t)
-        (funcall back-search-fn ioccur-search-pattern (point-at-bol) t))
+                     ioccur-pattern (point-at-eol) t)
+        (funcall back-search-fn ioccur-pattern (point-at-bol) t))
       (ioccur-color-matched-line))))
 
 ;;;###autoload
@@ -536,7 +536,7 @@ Move point to first occurence of `ioccur-search-pattern'."
         (or chr evt))))
 
 (defun ioccur-read-search-input (initial-input start-point)
-  "Read each keyboard input and add it to `ioccur-search-pattern'.
+  "Read each keyboard input and add it to `ioccur-pattern'.
 INITIAL-INPUT is a string given as default input, generally thing at point.
 START-POINT is the point where we start searching in buffer."
   (let* ((prompt         (propertize ioccur-search-prompt
@@ -552,7 +552,7 @@ START-POINT is the point where we start searching in 
buffer."
          yank-point)
     (unless (string= initial-input "")
       (loop for char across initial-input do (push char tmp-list)))
-    (setq ioccur-search-pattern initial-input)
+    (setq ioccur-pattern initial-input)
     ;; Cycle history function.
     ;;
     (flet ((cycle-hist (arg)
@@ -584,12 +584,12 @@ START-POINT is the point where we start searching in 
buffer."
                            (setq tmp-list nil)
                            (loop for char across cur-hist-elm
                               do (push char tmp-list))
-                           (setq ioccur-search-pattern cur-hist-elm)))
+                           (setq ioccur-pattern cur-hist-elm)))
                        ;; First call use car of history ring.
                        (setq tmp-list nil)
                        (loop for char across cur-hist-elm
                           do (push char tmp-list))
-                       (setq ioccur-search-pattern cur-hist-elm)
+                       (setq ioccur-pattern cur-hist-elm)
                        (setq start-hist t)))
                  (message "No history available.") (sit-for 2) t))
            ;; Insert INITIAL-INPUT.
@@ -610,7 +610,7 @@ START-POINT is the point where we start searching in 
buffer."
                (ioccur-cancel-search))))
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
-                          (concat prompt ioccur-search-pattern))))
+                          (concat prompt ioccur-pattern))))
                (message nil)
                (case char
                  ((not (?\M-p ?\M-n ?\t C-tab)) ; Reset history
@@ -655,7 +655,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
-                  (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
+                  (kill-new ioccur-pattern) (setq tmp-list ()) t)
                  (?\C-y                         ; Yank from `kill-ring'.
                   (setq initial-input (car kill-ring))
                   (insert-initial-input) t)
@@ -687,7 +687,7 @@ START-POINT is the point where we start searching in 
buffer."
                                            (this-single-command-raw-keys))
                                    unread-command-events))
                       nil))))
-        (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
+        (setq ioccur-pattern (apply 'string (reverse tmp-list)))))))
 
 (defun ioccur-print-buffer (regexp)
   "Pretty Print results matching REGEXP in `ioccur-buffer'."
@@ -744,7 +744,7 @@ M-p/n           Precedent and next `ioccur-history' 
element."))
          ioccur-search-delay 'repeat
          #'(lambda ()
              (ioccur-print-buffer
-              ioccur-search-pattern)))))
+              ioccur-pattern)))))
 
 
 ;;;###autoload
@@ -850,16 +850,16 @@ for commands provided in the `ioccur-buffer'."
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."
   ;; Push elm in history if not already there or empty.
-  (unless (or (member ioccur-search-pattern ioccur-history)
-              (string= ioccur-search-pattern ""))
-    (push ioccur-search-pattern ioccur-history))
+  (unless (or (member ioccur-pattern ioccur-history)
+              (string= ioccur-pattern ""))
+    (push ioccur-pattern ioccur-history))
   ;; If elm already exists in history ring
   ;; push it on top of stack.
   (let ((pos-hist-elm (ioccur-position
-                       ioccur-search-pattern
+                       ioccur-pattern
                        ioccur-history :test 'equal)))
     (unless (string= (car ioccur-history)
-                     ioccur-search-pattern)
+                     ioccur-pattern)
       (push (pop (nthcdr pos-hist-elm ioccur-history))
             ioccur-history)))
   (when (> (length ioccur-history) ioccur-max-length-history)

commit 34af020380c21e3bea25ed5f2f65f1ed208f15d8
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Aug 10 17:20:16 2010 +0200

    require wdired at compile time to shutup compiler.

diff --git a/ioccur.el b/ioccur.el
index 56c2cc0..5f82a2a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -48,6 +48,7 @@
 (require 'derived)
 (eval-when-compile (require 'cl))
 (require 'outline)
+(eval-when-compile (require 'wdired))
 
 (defvar ioccur-mode-map
   (let ((map (make-sparse-keymap)))
@@ -745,8 +746,7 @@ M-p/n           Precedent and next `ioccur-history' 
element."))
              (ioccur-print-buffer
               ioccur-search-pattern)))))
 
-(declare-function 'wdired-change-to-wdired-mode "wdired.el")
-(declare-function 'wdired-change-to-dired-mode "wdired.el")
+
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.

commit fac3de57832134d7d369eb5caec7b75c82736ebb
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Aug 10 11:22:53 2010 +0200

    declare wdired functions.

diff --git a/ioccur.el b/ioccur.el
index 021c778..56c2cc0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -744,7 +744,9 @@ M-p/n           Precedent and next `ioccur-history' 
element."))
          #'(lambda ()
              (ioccur-print-buffer
               ioccur-search-pattern)))))
-              
+
+(declare-function 'wdired-change-to-wdired-mode "wdired.el")
+(declare-function 'wdired-change-to-dired-mode "wdired.el")
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.

commit d7ab012541fbd6beae1aa4fc060814077f84888b
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Aug 10 08:42:10 2010 +0200

    (ioccur) maybe turn off wdired-mode and reenable when exit.

diff --git a/ioccur.el b/ioccur.el
index f164c05..021c778 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -450,8 +450,8 @@ Goto NUMLINE."
 (defun ioccur-jump ()
   "Jump to line in other buffer and put an overlay on it.
 Move point to first occurence of `ioccur-search-pattern'."
-  (let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
-         (pos  (string-to-number line))
+  (let* ((line           (buffer-substring (point-at-bol) (point-at-eol)))
+         (pos            (string-to-number line))
          (back-search-fn (if (eq ioccur-search-function 're-search-forward)
                              're-search-backward 'search-backward)))
     (unless (or (string= line "")
@@ -698,20 +698,20 @@ START-POINT is the point where we start searching in 
buffer."
                  'face 'ioccur-title-face
                  'help-echo
 "C-n or <down>  next line.\n
-C-p or <up>    precedent line.\n
-C-v and M-v    scroll up and down.\n
-C-z or <right> jump without quitting loop.\n
-C-j or <left>  jump and kill `ioccur-buffer'.\n
-RET            exit keeping `ioccur-buffer'.\n
-DEL            remove last character entered.\n
-C-k            Kill current input.\n
-C-w            Yank stuff at point.\n
-C-g            quit and restore buffer.\n
-C-|            Toggle split window.\n
-C-:            Toggle regexp/litteral search.\n
-C-down         Follow in other buffer.\n
-C-up           Follow in other buffer.\n
-M-p/n          Precedent and next `ioccur-history' element."))
+C-p or <up>     precedent line.\n
+C-v and M-v     scroll up and down.\n
+C-z or <right>  jump without quitting loop.\n
+C-j or <left>   jump and kill `ioccur-buffer'.\n
+RET             exit keeping `ioccur-buffer'.\n
+DEL             remove last character entered.\n
+C-k             Kill current input.\n
+C-w             Yank stuff at point.\n
+C-g             quit and restore buffer.\n
+C-|             Toggle split window.\n
+C-:             Toggle regexp/litteral search.\n
+C-down          Follow in other buffer.\n
+C-up            Follow in other buffer.\n
+M-p/n           Precedent and next `ioccur-history' element."))
            wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
@@ -804,6 +804,13 @@ for commands provided in the `ioccur-buffer'."
                            ""))
              (len      (length init-str))
              (curpos   (point))
+             (cur-mode (with-current-buffer ioccur-current-buffer
+                         (prog1
+                             major-mode
+                           ;; If current `major-mode' is wdired
+                           ;; Turn it off.
+                           (when (eq major-mode 'wdired-mode)
+                             (wdired-change-to-dired-mode)))))
              str-no-prop)
         (set-text-properties 0 len nil init-str)
         (setq str-no-prop init-str)
@@ -832,6 +839,8 @@ for commands provided in the `ioccur-buffer'."
                    (message nil) (ioccur-save-history))
                   (t                      ; Jump keeping `ioccur-buffer'.
                    (ioccur-jump) (other-window 1) (ioccur-save-history)))
+            ;; Maybe reenable `wdired-mode'.
+            (when (eq cur-mode 'wdired-mode) (wdired-change-to-wdired-mode))
             (setq ioccur-count-occurences 0)
             (setq ioccur-quit-flag nil)
             (setq ioccur-search-function ioccur-default-search-function))))))

commit d70c95da1f1474689e9963e16b2369c3ca1dd02e
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Aug 1 08:57:05 2010 +0200

    (ioccur-print-buffer) Add help-echo for commands in title.

diff --git a/ioccur.el b/ioccur.el
index 31eda56..f164c05 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -693,9 +693,25 @@ START-POINT is the point where we start searching in 
buffer."
   (let* ((cur-method (if (eq ioccur-search-function 're-search-forward)
                          "Regexp" "Literal"))
          (title (propertize
-                 (format "Ioccur %s searching (`C-:' to Toggle Method)"
+                 (format "* Ioccur %s searching * (`C-:' to Toggle Method, 
Mouse over for help.)"
                          cur-method)
-                 'face 'ioccur-title-face))
+                 'face 'ioccur-title-face
+                 'help-echo
+"C-n or <down>  next line.\n
+C-p or <up>    precedent line.\n
+C-v and M-v    scroll up and down.\n
+C-z or <right> jump without quitting loop.\n
+C-j or <left>  jump and kill `ioccur-buffer'.\n
+RET            exit keeping `ioccur-buffer'.\n
+DEL            remove last character entered.\n
+C-k            Kill current input.\n
+C-w            Yank stuff at point.\n
+C-g            quit and restore buffer.\n
+C-|            Toggle split window.\n
+C-:            Toggle regexp/litteral search.\n
+C-down         Follow in other buffer.\n
+C-up           Follow in other buffer.\n
+M-p/n          Precedent and next `ioccur-history' element."))
            wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))

commit a32f451ce9d7e71072a3ab66fec7d05b16b1f1a9
Merge: 1f48179 523e59e
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jul 29 21:44:57 2010 +0200

    Merge tags from default.


commit 523e59e0dd743a4e64bc250bdbfefa2b11cc7724
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jul 29 21:43:07 2010 +0200

    Added tag V-1.8 for changeset c61c580d22c0

commit 87a5b8ebbcae6f4b661de1877026c5a567a69272
Merge: 1f48179 44b0024
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Jul 29 21:40:32 2010 +0200

    Merge dev branch in default.


commit 1f4817900540e77273c7684083986216ef92aa07
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Jul 21 15:24:57 2010 +0200

    (ioccur-mode-line-string) a little shorter.

diff --git a/ioccur.el b/ioccur.el
index 6079d0e..31eda56 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -89,10 +89,10 @@
 (defcustom ioccur-mode-line-string
   (if (window-system)
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
-C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
+C-n/p:Next/Prec, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
 
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
-C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank 
tap")
+C-n/p:Next/Prec, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
 
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."

commit a0af076da0f1059f6de229b7983406583db995c2
Merge: dcd78c1 44b0024
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Jul 19 14:39:39 2010 +0200

    Merge.


commit dcd78c1acb1e93a1c4b74a1da6b6ff8a0cd52ca9
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Jul 19 14:37:04 2010 +0200

    Add comments and fix some docstring No code change.

diff --git a/ioccur.el b/ioccur.el
index 5b45bf4..6079d0e 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -161,19 +161,31 @@ Use here one of `re-search-forward' or `search-forward'."
 
 
 ;;; Internal variables.
+;; String entered in prompt.
 (defvar ioccur-search-pattern "")
+;; The ioccur timer.
 (defvar ioccur-search-timer nil)
+;; Signal C-g hit.
 (defvar ioccur-quit-flag nil)
+;; The buffer we search in.
 (defvar ioccur-current-buffer nil)
+;; The overlay in `ioccur-buffer'.
 (defvar ioccur-occur-overlay nil)
 (make-variable-buffer-local 'ioccur-occur-overlay)
+;; Signal we quit and kill `ioccur-buffer'.
 (defvar ioccur-exit-and-quit-p nil)
+;; A list to store history.
 (defvar ioccur-history nil)
+;; The overlay in `ioccur-current-buffer'.
 (defvar ioccur-match-overlay nil)
+;; Number of occurences found.
 (defvar ioccur-count-occurences 0)
+;;The buffer where we send results.
 (defvar ioccur-buffer nil)
 (make-variable-buffer-local 'ioccur-buffer)
+;; True when jumping to a founded occurence.
 (defvar ioccur-success nil)
+;; Search function actually in use.
 (defvar ioccur-search-function ioccur-default-search-function)
 
 (define-derived-mode ioccur-mode
@@ -247,8 +259,7 @@ Special commands:
                    (ioccur-iter-next iterator)))))))
 
 (defun ioccur-print-results (regexp)
-  "Print in `ioccur-buffer' all lines matching REGEXP found in BUFFER.
-BUFFER default value is `ioccur-current-buffer'."
+  "Print in `ioccur-buffer' lines matching REGEXP in `ioccur-current-buffer'."
   (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
     (save-excursion
@@ -267,8 +278,7 @@ BUFFER default value is `ioccur-current-buffer'."
          do (forward-line 1)))))
 
 (defun ioccur-print-line (line nline)
-  "Prepare and insert a matched LINE at line number NLINE in BUFFER.
-BUFFER default value is `ioccur-buffer'."
+  "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let ((lineno     (int-to-string (1+ nline)))
           (trunc-line (ioccur-truncate-line line)))
@@ -279,7 +289,7 @@ BUFFER default value is `ioccur-buffer'."
               ":" trunc-line "\n"))))
 
 (defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
-  "Remove indentation and truncate LINE to COLUMNS.
+  "Remove indentation and truncate LINE of num COLUMNS.
 COLUMNS default value is `ioccur-length-line'."
   (let* ((bol-reg (if (string-match "^\t" line)
                       "\\(^\t*\\)" "\\(^ *\\)"))
@@ -412,7 +422,7 @@ See `ioccur-find-buffer-matching1'."
   (delete-other-windows))
 
 (defun ioccur-goto-line (numline)
-  "Non--interactive version of `goto-line.'.
+  "Non--interactive version of `goto-line'.
 Goto NUMLINE."
   (goto-char (point-min)) (forward-line (1- numline)))
 

commit 44b0024859129ab4fc4904e809a2447086a9c149
Merge: d2b4a32 a72b4ed
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jul 18 18:32:16 2010 +0200

    Merge branchs.


commit d2b4a3243571483992c4565150505a6c4b30f81d
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jul 18 18:14:17 2010 +0200

    (ioccur-jump) Use the right function depending method in use.

diff --git a/ioccur.el b/ioccur.el
index 20c01f3..5b45bf4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -441,7 +441,9 @@ Goto NUMLINE."
   "Jump to line in other buffer and put an overlay on it.
 Move point to first occurence of `ioccur-search-pattern'."
   (let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
-         (pos  (string-to-number line)))
+         (pos  (string-to-number line))
+         (back-search-fn (if (eq ioccur-search-function 're-search-forward)
+                             're-search-backward 'search-backward)))
     (unless (or (string= line "")
                 (string= line "Ioccur"))
       (pop-to-buffer ioccur-current-buffer t)
@@ -449,8 +451,9 @@ Move point to first occurence of `ioccur-search-pattern'."
       (ioccur-goto-line pos)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-search-pattern'.
-      (when (re-search-forward ioccur-search-pattern (point-at-eol) t)
-        (re-search-backward ioccur-search-pattern (point-at-bol) t))
+      (when (funcall ioccur-search-function
+                     ioccur-search-pattern (point-at-eol) t)
+        (funcall back-search-fn ioccur-search-pattern (point-at-bol) t))
       (ioccur-color-matched-line))))
 
 ;;;###autoload
@@ -678,7 +681,7 @@ START-POINT is the point where we start searching in 
buffer."
 (defun ioccur-print-buffer (regexp)
   "Pretty Print results matching REGEXP in `ioccur-buffer'."
   (let* ((cur-method (if (eq ioccur-search-function 're-search-forward)
-                        "Regexp" "Literal"))
+                         "Regexp" "Literal"))
          (title (propertize
                  (format "Ioccur %s searching (`C-:' to Toggle Method)"
                          cur-method)

commit 141e5bbc800637beff657c5c86f966e02e20340d
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jul 18 15:09:43 2010 +0200

    Provide toggle search method (literal or regexp)
    
    (ioccur-default-search-function, ioccur-search-function) new.
    (ioccur-print-results) funcall method.
    (ioccur-read-search-input) C-: toggle method.
    (ioccur-print-buffer) Notify method in use and how to toggle.
    (ioccur) reset initial method when exit.

diff --git a/ioccur.el b/ioccur.el
index c958a57..20c01f3 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -122,6 +122,12 @@ To have ido completion, you have to enable `ido-mode'."
   :group 'ioccur
   :type 'symbol)
 
+(defcustom ioccur-default-search-function 're-search-forward
+  "*Default search function.
+Use here one of `re-search-forward' or `search-forward'."
+  :group 'ioccur
+  :type 'symbol)
+
 ;;; Faces.
 (defface ioccur-overlay-face
     '((t (:background "Green4" :underline t)))
@@ -168,6 +174,7 @@ To have ido completion, you have to enable `ido-mode'."
 (defvar ioccur-buffer nil)
 (make-variable-buffer-local 'ioccur-buffer)
 (defvar ioccur-success nil)
+(defvar ioccur-search-function ioccur-default-search-function)
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -254,7 +261,7 @@ BUFFER default value is `ioccur-current-buffer'."
          ;; and we have no chance to exit loop.
          when quit-flag do (setq ioccur-quit-flag t) and return nil
          for count from 0
-         when (re-search-forward regexp (point-at-eol) t)
+         when (funcall ioccur-search-function regexp (point-at-eol) t)
          do (ioccur-print-line
              (buffer-substring (point-at-bol) (point-at-eol)) count)
          do (forward-line 1)))))
@@ -625,6 +632,10 @@ START-POINT is the point where we start searching in 
buffer."
                   (ioccur-scroll-other-window-up) t)
                  (?\C-|                         ; Toggle split window.
                   (ioccur-split-window) t)
+                 (?\C-:                         ; Toggle regexp/litteral 
search.
+                  (if (eq ioccur-search-function 're-search-forward)
+                      (setq ioccur-search-function 'search-forward)
+                      (setq ioccur-search-function 're-search-forward)) t)
                  (?\C-k                         ; Kill input.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
@@ -666,8 +677,13 @@ START-POINT is the point where we start searching in 
buffer."
 
 (defun ioccur-print-buffer (regexp)
   "Pretty Print results matching REGEXP in `ioccur-buffer'."
-  (let ((title (propertize "Ioccur" 'face 'ioccur-title-face))
-        wrong-regexp)
+  (let* ((cur-method (if (eq ioccur-search-function 're-search-forward)
+                        "Regexp" "Literal"))
+         (title (propertize
+                 (format "Ioccur %s searching (`C-:' to Toggle Method)"
+                         cur-method)
+                 'face 'ioccur-title-face))
+           wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
         (erase-buffer)
@@ -717,6 +733,8 @@ DEL            remove last character entered.
 C-k            Kill current input.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
+C-|            Toggle split window.
+C-:            Toggle regexp/litteral search.
 C-down         Follow in other buffer.
 C-up           Follow in other buffer.
 M-p/n          Precedent and next `ioccur-history' element:
@@ -786,7 +804,8 @@ for commands provided in the `ioccur-buffer'."
                   (t                      ; Jump keeping `ioccur-buffer'.
                    (ioccur-jump) (other-window 1) (ioccur-save-history)))
             (setq ioccur-count-occurences 0)
-            (setq ioccur-quit-flag nil))))))
+            (setq ioccur-quit-flag nil)
+            (setq ioccur-search-function ioccur-default-search-function))))))
 
 (defun ioccur-save-history ()
   "Save last ioccur element found in `ioccur-history'."

commit ef5bbccbfe384d0a9a73f888e4cde669e8d4f9c7
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jul 17 09:25:32 2010 +0200

    (ioccur-print-buffer) keep improving error message.

diff --git a/ioccur.el b/ioccur.el
index 92b8882..c958a57 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -678,9 +678,9 @@ START-POINT is the point where we start searching in 
buffer."
         (if wrong-regexp
             (insert
              title "\n\n"
-             (propertize "Invalid Expression: "
+             (propertize "Invalid Regexp: "
                          'face 'ioccur-invalid-regexp)
-             (format "`%s'" regexp) "\n\n")
+             (format "No match for `%s'" regexp) "\n\n")
             (insert title "\n\n"
                     (propertize (format "Found %s occurences matching "
                                         ioccur-count-occurences)

commit 59797ac65d9592f5868ab000a9c16aaa3f0f3aa4
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jul 17 06:50:03 2010 +0200

    Put point on empty line when invalid regexp to exit properly on RET.
    
    (ioccur-invalid-regexp) New face.

diff --git a/ioccur.el b/ioccur.el
index 3321a31..92b8882 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -148,6 +148,12 @@ To have ido completion, you have to enable `ido-mode'."
   "Face for highlight number line in ioccur buffer."
   :group 'ioccur-faces)
 
+(defface ioccur-invalid-regexp
+    '((t (:foreground "Goldenrod")))
+  "Face for highlight wrong regexp message in ioccur buffer."
+  :group 'ioccur-faces)
+
+
 ;;; Internal variables.
 (defvar ioccur-search-pattern "")
 (defvar ioccur-search-timer nil)
@@ -671,10 +677,10 @@ START-POINT is the point where we start searching in 
buffer."
         (goto-char (point-min))
         (if wrong-regexp
             (insert
-             title "\n\n>> "
+             title "\n\n"
              (propertize "Invalid Expression: "
-                         'face '((:foreground "red")))
-             regexp)
+                         'face 'ioccur-invalid-regexp)
+             (format "`%s'" regexp) "\n\n")
             (insert title "\n\n"
                     (propertize (format "Found %s occurences matching "
                                         ioccur-count-occurences)

commit 73a0bea3f6265940279952c85c7efa40e60bd3d6
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 16 18:31:11 2010 +0200

    (ioccur-print-buffer) Use 'matching' in message.

diff --git a/ioccur.el b/ioccur.el
index 0ee69ec..3321a31 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -676,7 +676,7 @@ START-POINT is the point where we start searching in 
buffer."
                          'face '((:foreground "red")))
              regexp)
             (insert title "\n\n"
-                    (propertize (format "Found %s occurences of "
+                    (propertize (format "Found %s occurences matching "
                                         ioccur-count-occurences)
                                 'face 'underline)
                     (propertize regexp 'face 'ioccur-regexp-face)

commit a56d839a1fea083776256cf239efe77ec6da7bdc
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 16 17:04:51 2010 +0200

    (ioccur-print-buffer) Improve error message.

diff --git a/ioccur.el b/ioccur.el
index 91a985f..0ee69ec 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -672,8 +672,9 @@ START-POINT is the point where we start searching in 
buffer."
         (if wrong-regexp
             (insert
              title "\n\n>> "
-             (propertize "Incomplete Expression"
-                         'face '((:foreground "red"))))
+             (propertize "Invalid Expression: "
+                         'face '((:foreground "red")))
+             regexp)
             (insert title "\n\n"
                     (propertize (format "Found %s occurences of "
                                         ioccur-count-occurences)

commit 4df15bd94b1758d368c3c131319e6cff841acfdb
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 16 16:19:34 2010 +0200

    (ioccur-print-buffer) Send message until complete regexp is entered.

diff --git a/ioccur.el b/ioccur.el
index 0b7be88..91a985f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -660,23 +660,29 @@ START-POINT is the point where we start searching in 
buffer."
 
 (defun ioccur-print-buffer (regexp)
   "Pretty Print results matching REGEXP in `ioccur-buffer'."
-  (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
+  (let ((title (propertize "Ioccur" 'face 'ioccur-title-face))
+        wrong-regexp)
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
         (erase-buffer)
-        (condition-case nil
+        (condition-case err
             (ioccur-print-results regexp)
-          (error nil))
+          (error (setq wrong-regexp t)))
         (goto-char (point-min))
-        (insert title "\n\n"
-                (propertize (format "Found %s occurences of "
-                                    ioccur-count-occurences)
-                            'face 'underline)
-                (propertize regexp 'face 'ioccur-regexp-face)
-                (propertize
-                 (format " in %s" ioccur-current-buffer)
-                 'face 'underline) "\n\n")
-        (ioccur-color-current-line))))
+        (if wrong-regexp
+            (insert
+             title "\n\n>> "
+             (propertize "Incomplete Expression"
+                         'face '((:foreground "red"))))
+            (insert title "\n\n"
+                    (propertize (format "Found %s occurences of "
+                                        ioccur-count-occurences)
+                                'face 'underline)
+                    (propertize regexp 'face 'ioccur-regexp-face)
+                    (propertize
+                     (format " in %s" ioccur-current-buffer)
+                     'face 'underline) "\n\n")
+            (ioccur-color-current-line)))))
 
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."

commit c1648c31e5522235b2f1a1742fa88a002353b5e8
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jul 10 19:58:58 2010 +0200

    (ioccur-print-buffer) Fix: Put ioccur-print-results in a condition-case to 
not return error when regexp is invalid.

diff --git a/ioccur.el b/ioccur.el
index b3e1e03..0b7be88 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -664,7 +664,9 @@ START-POINT is the point where we start searching in 
buffer."
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
         (erase-buffer)
-        (ioccur-print-results regexp)
+        (condition-case nil
+            (ioccur-print-results regexp)
+          (error nil))
         (goto-char (point-min))
         (insert title "\n\n"
                 (propertize (format "Found %s occurences of "

commit 123dff37f4d7eb8a0136799e9a9b91504f1a705a
Author: Chris Wanstrath <address@hidden>
Date:   Fri Jul 9 14:45:52 2010 -0400

    Typo in README

diff --git a/README.md b/README.md
index f279d67..e680e21 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ Well, idiomatic CoffeeScript uses two spaces. We can set our
       "coffee-mode-hook"
      (set (make-local-variable 'tab-width) 2))
 
-    (add-hook coffee-mode-hook
+    (add-hook 'coffee-mode-hook
       '(lambda() (coffee-custom)))
 
 For more configuration options and another example of this hook, look

commit 254d4364938cbde4b1d90f93a58ffc51134a666c
Merge: a72b4ed cb8a4a9
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 9 12:47:34 2010 +0200

    Merge tags.


commit a72b4edf3d7e47d48bee18b64b9614f236e40afc
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 9 12:46:35 2010 +0200

    Added tag V-1.7 for changeset 3a6ac8031e34

commit 7835875a58a6f45d342106a1fe7d7b7a83684257
Merge: ae85d44 cb8a4a9
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jul 9 12:45:57 2010 +0200

    Merge branchs.


commit cb8a4a9f934efee8779bfac80d906c9a9344646d
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Jul 3 15:22:24 2010 +0200

    Require outline (for show-all)

diff --git a/ioccur.el b/ioccur.el
index 9970d8a..b3e1e03 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -47,6 +47,7 @@
 ;;; Code:
 (require 'derived)
 (eval-when-compile (require 'cl))
+(require 'outline)
 
 (defvar ioccur-mode-map
   (let ((map (make-sparse-keymap)))

commit b1c16e50e93c662a12c49ac8f18b607656238361
Author: Chris Wanstrath <address@hidden>
Date:   Mon Jun 21 11:22:19 2010 -0700

    Use after-save-hook in example to grab actual file contents.

diff --git a/README.md b/README.md
index 5df856a..f279d67 100644
--- a/README.md
+++ b/README.md
@@ -212,7 +212,7 @@ Naturally. Example:
       (setq coffee-command "~/dev/coffee"))
 
       ;; Compile JS on every save, unless it's a Cakefile.
-      (add-hook 'before-save-hook
+      (add-hook 'after-save-hook
           '(lambda ()
              (when (not (string= (buffer-name) "Cakefile"))
               (coffee-compile-file))))

commit f698b2db0b232eca879c0ce245baec8df5f5acd1
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jun 20 21:40:43 2010 +0200

    (ioccur-dired) test if file is a directory

diff --git a/ioccur.el b/ioccur.el
index 0f3e9b3..9970d8a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -375,6 +375,7 @@ See `ioccur-find-buffer-matching1'."
                                              (thing-at-point 'symbol)))))
   (let ((buf-list (loop for f in (dired-get-marked-files)
                      do (find-file-noselect f)
+                     unless (file-directory-p f)
                      collect (get-buffer (file-name-nondirectory f)))))
     (ioccur-find-buffer-matching1 regexp nil buf-list)))
 

commit fcb21ed23acb3702540d07a98dd26fa4181eb109
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jun 20 12:47:22 2010 +0200

    (ioccur-find-buffer-matching1) save win conf before doing anything.
    (ioccur-dired) new.

diff --git a/ioccur.el b/ioccur.el
index 671a0d9..0f3e9b3 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -325,12 +325,12 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
            finally return hist))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
+        (win-conf (current-window-configuration))
         (buf-list (if match-buf-name
                       (ioccur-list-buffers-matching
                        (read-string "In Buffer names matching: ")
                        regexp buffer-list)
-                      (ioccur-list-buffers-containing regexp buffer-list)))
-        (win-conf (current-window-configuration)))
+                      (ioccur-list-buffers-containing regexp buffer-list))))
 
     (labels
         ((find-buffer ()
@@ -366,6 +366,18 @@ See `ioccur-find-buffer-matching1'."
                                              (thing-at-point 'symbol)))))
   (ioccur-find-buffer-matching1 regexp current-prefix-arg))
 
+;;; Ioccur dired
+;;;###autoload
+(defun ioccur-dired (regexp)
+  (interactive (list (let ((savehist-save-minibuffer-history nil))
+                       (read-from-minibuffer "Search for Pattern: "
+                                             nil nil nil '(ioccur-history . 0)
+                                             (thing-at-point 'symbol)))))
+  (let ((buf-list (loop for f in (dired-get-marked-files)
+                     do (find-file-noselect f)
+                     collect (get-buffer (file-name-nondirectory f)))))
+    (ioccur-find-buffer-matching1 regexp nil buf-list)))
+
 ;;;###autoload
 (defun ioccur-restart ()
   "Restart `ioccur' from `ioccur-buffer'.

commit f25bfbc22b5e983087f942140ce886da64e1ce1b
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Jun 20 10:57:36 2010 +0200

    (ioccur-list-buffers-matching, ioccur-list-buffers-containing) Use extra 
arg buffer-list.
    (ioccur-find-buffer-matching1) generic function.
    (ioccur-find-buffer-matching) call interactively 
ioccur-find-buffer-matching1.

diff --git a/ioccur.el b/ioccur.el
index 8b4cab4..671a0d9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -280,11 +280,11 @@ COLUMNS default value is `ioccur-length-line'."
       (goto-char (point-min))
       (when (re-search-forward regexp nil t) buffer))))
 
-(defun ioccur-list-buffers-matching (buffer-match regexp)
-  "Return a list of all buffer with name matching BUFFER-MATCH and \
-containing lines matching REGEXP."
+(defun ioccur-list-buffers-matching (buffer-match regexp buffer-list)
+  "Collect all buffers in BUFFER-LIST whose names match BUFFER-MATCH and \
+contain lines matching REGEXP."
   (loop
-     with ini-buf-list = (loop for buf in (buffer-list)
+     with ini-buf-list = (loop for buf in buffer-list
                             unless (rassq buf dired-buffers)
                             collect buf)
      for buf in ini-buf-list
@@ -293,22 +293,23 @@ containing lines matching REGEXP."
                (ioccur-buffer-contain buf regexp))
      collect bname))
 
-(defun ioccur-list-buffers-containing (regexp)
-  "Return a list of all existing buffers filename containing \
-lines matching REGEXP."
-  (loop with buf-list = (loop for i in (buffer-list)
+(defun ioccur-list-buffers-containing (regexp buffer-list)
+  "Collect all buffers in BUFFER-LIST containing lines matching REGEXP."
+  (loop with buf-list = (loop for i in buffer-list
                            when (buffer-file-name (get-buffer i))
                            collect i)
      for buf in buf-list
      when (ioccur-buffer-contain buf regexp)
      collect (buffer-name buf)))
 
-;;;###autoload
-(defun ioccur-find-buffer-matching (regexp)
+(defun* ioccur-find-buffer-matching1 (regexp
+                                      &optional
+                                      match-buf-name
+                                      (buffer-list (buffer-list)))
   "Find all buffers containing a text matching REGEXP \
 and connect `ioccur' to the selected one.
 
-With a prefix arg search is performed only in buffers
+If MATCH-BUF-NAME is non--nil search is performed only in buffers
 with name matching specified expression (prompt).
 
 Hitting C-g in a `ioccur' session will return to completion list.
@@ -317,10 +318,6 @@ Hitting C-g in the completion list will jump back to 
initial buffer.
 The buffer completion list is provided by one of:
 `anything-comp-read', `ido-completing-read', `completing-read'
 depending on which `ioccur-buffer-completion-style' you have choosen."
-  (interactive (list (let ((savehist-save-minibuffer-history nil))
-                       (read-from-minibuffer "Search for Pattern: "
-                                             nil nil nil '(ioccur-history . 0)
-                                             (thing-at-point 'symbol)))))
   ;; Remove doublons maybe added by minibuffer in `ioccur-history'.
   (setq ioccur-history
         (loop with hist for i in ioccur-history
@@ -328,10 +325,11 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
            finally return hist))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
-        (buf-list (if current-prefix-arg
+        (buf-list (if match-buf-name
                       (ioccur-list-buffers-matching
-                       (read-string "In Buffer names matching: ") regexp)
-                      (ioccur-list-buffers-containing regexp)))
+                       (read-string "In Buffer names matching: ")
+                       regexp buffer-list)
+                      (ioccur-list-buffers-containing regexp buffer-list)))
         (win-conf (current-window-configuration)))
 
     (labels
@@ -359,6 +357,16 @@ depending on which `ioccur-buffer-completion-style' you 
have choosen."
       (find-buffer))))
 
 ;;;###autoload
+(defun ioccur-find-buffer-matching (regexp)
+  "Find all buffers containing a text matching REGEXP.
+See `ioccur-find-buffer-matching1'."
+  (interactive (list (let ((savehist-save-minibuffer-history nil))
+                       (read-from-minibuffer "Search for Pattern: "
+                                             nil nil nil '(ioccur-history . 0)
+                                             (thing-at-point 'symbol)))))
+  (ioccur-find-buffer-matching1 regexp current-prefix-arg))
+
+;;;###autoload
 (defun ioccur-restart ()
   "Restart `ioccur' from `ioccur-buffer'.
 `ioccur-buffer' is erased and a new search is started."

commit c1287e83c8899e896bf86db807c14e523f5c20fe
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Jun 9 17:37:20 2010 +0200

    (ioccur-find-buffer-matching) Fix docstring. No code change.

diff --git a/ioccur.el b/ioccur.el
index 1f0f738..8b4cab4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -305,11 +305,18 @@ lines matching REGEXP."
 
 ;;;###autoload
 (defun ioccur-find-buffer-matching (regexp)
-  "Find an existing buffer containing an expression matching REGEXP \
-and connect `ioccur' to it.
-With a prefix arg search in buffer matching specified expression.
-Hitting C-g in a `ioccur' session will return to buffer completion list.
-Hitting C-g in the buffer completion list will jump back to initial buffer."
+  "Find all buffers containing a text matching REGEXP \
+and connect `ioccur' to the selected one.
+
+With a prefix arg search is performed only in buffers
+with name matching specified expression (prompt).
+
+Hitting C-g in a `ioccur' session will return to completion list.
+Hitting C-g in the completion list will jump back to initial buffer.
+
+The buffer completion list is provided by one of:
+`anything-comp-read', `ido-completing-read', `completing-read'
+depending on which `ioccur-buffer-completion-style' you have choosen."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
                        (read-from-minibuffer "Search for Pattern: "
                                              nil nil nil '(ioccur-history . 0)

commit cbe56ea70c388b5404edbf5d80c4c9f9ef407afd
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jun 4 14:54:49 2010 +0200

    (ioccur-jump) show-all

diff --git a/ioccur.el b/ioccur.el
index 1ceaaf9..1f0f738 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -403,6 +403,7 @@ Move point to first occurence of `ioccur-search-pattern'."
     (unless (or (string= line "")
                 (string= line "Ioccur"))
       (pop-to-buffer ioccur-current-buffer t)
+      (show-all) ; For org and outline enabled buffers.
       (ioccur-goto-line pos)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-search-pattern'.

commit 2ef8bb1482de371b7b53e8be8f19aeebd03970bd
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Jun 4 12:12:20 2010 +0200

    (ioccur-find-buffer-matching) Remove doublons maybe added by minibuffer in 
`ioccur-history'.

diff --git a/ioccur.el b/ioccur.el
index 221eebc..1ceaaf9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -314,6 +314,11 @@ Hitting C-g in the buffer completion list will jump back 
to initial buffer."
                        (read-from-minibuffer "Search for Pattern: "
                                              nil nil nil '(ioccur-history . 0)
                                              (thing-at-point 'symbol)))))
+  ;; Remove doublons maybe added by minibuffer in `ioccur-history'.
+  (setq ioccur-history
+        (loop with hist for i in ioccur-history
+           when (not (member i hist)) collect i into hist
+           finally return hist))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg

commit 5745bc9ed8069890b227552d1a22d97336dfb7d4
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jun 1 17:19:56 2010 +0200

    (ioccur-find-buffer-matching) reindent

diff --git a/ioccur.el b/ioccur.el
index 8811e97..221eebc 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -312,8 +312,8 @@ Hitting C-g in a `ioccur' session will return to buffer 
completion list.
 Hitting C-g in the buffer completion list will jump back to initial buffer."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
                        (read-from-minibuffer "Search for Pattern: "
-                                    nil nil nil '(ioccur-history . 0)
-                                    (thing-at-point 'symbol)))))
+                                             nil nil nil '(ioccur-history . 0)
+                                             (thing-at-point 'symbol)))))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg

commit 8e87ad5d17da5d7ca00c9c31934db4f60f4c232d
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Jun 1 15:53:20 2010 +0200

    (ioccur-find-matching-buffer) Use read-from-minibuffer.

diff --git a/ioccur.el b/ioccur.el
index aa4e05d..8811e97 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -311,9 +311,9 @@ With a prefix arg search in buffer matching specified 
expression.
 Hitting C-g in a `ioccur' session will return to buffer completion list.
 Hitting C-g in the buffer completion list will jump back to initial buffer."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
-                       (read-string "Search for Pattern: "
-                                    (thing-at-point 'symbol)
-                                    '(ioccur-history . 0)))))
+                       (read-from-minibuffer "Search for Pattern: "
+                                    nil nil nil '(ioccur-history . 0)
+                                    (thing-at-point 'symbol)))))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg

commit 26f308a2f6c18635fc9be9459121372879ec5fa9
Merge: a1e0b73 ae85d44
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 14:10:56 2010 +0200

    Merge tags.


commit ae85d44d033afb3ee89b1b073da5403d9e99a27d
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 14:10:05 2010 +0200

    Added tag V-1.6 for changeset 0543ff89bf5e

commit cd7b0306d711ba9b649621f9eeddb7fe606fa376
Merge: a1e0b73 7abb893
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 14:09:40 2010 +0200

    Merge branchs.


commit a1e0b73202b7b64b0f6bf49ee21764a085fd7f2d
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 10:41:19 2010 +0200

    (ioccur-find-buffer-matching) Improve prompt name.

diff --git a/ioccur.el b/ioccur.el
index 569039d..aa4e05d 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -318,7 +318,7 @@ Hitting C-g in the buffer completion list will jump back to 
initial buffer."
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg
                       (ioccur-list-buffers-matching
-                       (read-string "In Buffer matching: ") regexp)
+                       (read-string "In Buffer names matching: ") regexp)
                       (ioccur-list-buffers-containing regexp)))
         (win-conf (current-window-configuration)))
 

commit 25eaae7433f9649c96733d3fc36287a1f24f6b35
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 10:29:57 2010 +0200

    (ioccur-buffer-completion-style) New user variable.

diff --git a/ioccur.el b/ioccur.el
index 8c3f02e..569039d 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -108,6 +108,19 @@ Set it to nil to remove doc in mode-line."
   :group 'ioccur
   :type 'integer)
 
+(defcustom ioccur-buffer-completion-style 'anything
+  "*Type of completing read style you prefer to choose buffers \
+in `ioccur-find-buffer-matching'.
+It can be one of 'anything or 'ido.
+When nil or if anything is not found or `ido-mode' is off,
+fallback to classic `completing-read'.
+NOTE:
+To have anything completion you need a recent version of
+`anything-config.el'.
+To have ido completion, you have to enable `ido-mode'."
+  :group 'ioccur
+  :type 'symbol)
+
 ;;; Faces.
 (defface ioccur-overlay-face
     '((t (:background "Green4" :underline t)))
@@ -311,9 +324,11 @@ Hitting C-g in the buffer completion list will jump back 
to initial buffer."
 
     (labels
         ((find-buffer ()
-           (let ((buf (cond ((fboundp 'anything-comp-read)
+           (let ((buf (cond ((and (fboundp 'anything-comp-read)
+                                  (eq ioccur-buffer-completion-style 
'anything))
                              (anything-comp-read prompt buf-list :must-match 
t))
-                            (ido-mode
+                            ((and ido-mode
+                                  (eq ioccur-buffer-completion-style 'ido))
                              (ido-completing-read prompt buf-list nil t))
                             (t (completing-read prompt buf-list nil t)))))
              (unwind-protect

commit 99cd72e272b0a940dd95cb26f75a469855cb5a23
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 09:38:46 2010 +0200

    (ioccur-find-buffer-matching) Remove now unuseful return-from, add comments.

diff --git a/ioccur.el b/ioccur.el
index f5f1077..8c3f02e 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -260,7 +260,7 @@ COLUMNS default value is `ioccur-length-line'."
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
-(defun ioccur-buffer-contain (regexp buffer)
+(defun ioccur-buffer-contain (buffer regexp)
   "Return BUFFER if it contain an occurence of REGEXP."
   (with-current-buffer buffer
     (save-excursion
@@ -268,7 +268,7 @@ COLUMNS default value is `ioccur-length-line'."
       (when (re-search-forward regexp nil t) buffer))))
 
 (defun ioccur-list-buffers-matching (buffer-match regexp)
-  "Return a list of all buffer with name matching BUFFER-NAME and\
+  "Return a list of all buffer with name matching BUFFER-MATCH and \
 containing lines matching REGEXP."
   (loop
      with ini-buf-list = (loop for buf in (buffer-list)
@@ -277,21 +277,22 @@ containing lines matching REGEXP."
      for buf in ini-buf-list
      for bname = (buffer-name buf)
      when (and (string-match buffer-match bname)
-               (ioccur-buffer-contain regexp buf))
+               (ioccur-buffer-contain buf regexp))
      collect bname))
 
 (defun ioccur-list-buffers-containing (regexp)
-  "Return a list of all existing buffers containing lines matching REGEXP."
+  "Return a list of all existing buffers filename containing \
+lines matching REGEXP."
   (loop with buf-list = (loop for i in (buffer-list)
                            when (buffer-file-name (get-buffer i))
                            collect i)
      for buf in buf-list
-     when (ioccur-buffer-contain regexp buf)
+     when (ioccur-buffer-contain buf regexp)
      collect (buffer-name buf)))
 
 ;;;###autoload
-(defun* ioccur-find-buffer-matching (regexp)
-  "Find an existing buffer containing an expression matching REGEXP\
+(defun ioccur-find-buffer-matching (regexp)
+  "Find an existing buffer containing an expression matching REGEXP \
 and connect `ioccur' to it.
 With a prefix arg search in buffer matching specified expression.
 Hitting C-g in a `ioccur' session will return to buffer completion list.
@@ -319,11 +320,14 @@ Hitting C-g in the buffer completion list will jump back 
to initial buffer."
                   (progn
                     (switch-to-buffer buf)
                     (ioccur regexp)
+                    ;; Exit if we jump to this `ioccur-current-buffer',
+                    ;; otherwise, if C-g is hitten,
+                    ;; go back to buffer completion list.
                     (unless ioccur-success
                       (find-buffer)))
+               ;; C-g hit in buffer completion restore window config.
                (unless ioccur-success
-                 (set-window-configuration win-conf)
-                 (return-from ioccur-find-buffer-matching))))))
+                 (set-window-configuration win-conf))))))
 
       (find-buffer))))
 

commit 42c3c02172b08c2f2403be861a2a15f68c377983
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 28 08:53:38 2010 +0200

    (ioccur-find-buffer-matching) Use thing-at-point instead of car history for 
initial input.

diff --git a/ioccur.el b/ioccur.el
index 8ea15b5..f5f1077 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -298,8 +298,8 @@ Hitting C-g in a `ioccur' session will return to buffer 
completion list.
 Hitting C-g in the buffer completion list will jump back to initial buffer."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
                        (read-string "Search for Pattern: "
-                                    (car ioccur-history)
-                                    '(ioccur-history . 1)))))
+                                    (thing-at-point 'symbol)
+                                    '(ioccur-history . 0)))))
 
   (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg

commit 32a32b28e1c3f1b0e3da0ea6205b5ed561ca02ce
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 27 19:30:09 2010 +0200

    Add some infos in headers.

diff --git a/ioccur.el b/ioccur.el
index cf93d5a..8ea15b5 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -29,13 +29,20 @@
 ;;
 ;; Add this file to your `load-path', BYTE-COMPILE it and
 ;; add (require 'ioccur) in your .emacs.
-;; Start with M-x ioccur
+;;
+;; Start with (C-u) M-x ioccur
+;;            or
+;;            (C-u) M-x ioccur-find-buffer-matching
+;;
+;; Do C-h f ioccur or ioccur-find-buffer-matching for more info.
 
 ;;; Commentary:
 ;;
-;; You may want to save `ioccur-history', you can do that if you
-;; use desktop, adding that to your .emacs:
+;; To save `ioccur-history', use desktop, adding that to your .emacs:
 ;; (add-to-list 'desktop-globals-to-save 'ioccur-history)
+;;
+;; For more info See:
+;; [EVAL] (info "(emacs) saving emacs sessions")
 
 ;;; Code:
 (require 'derived)

commit 77d413a608bdeaf74e000a3ac102333abe14af0d
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 27 17:51:28 2010 +0200

    Minor change, just change the prompt in ioccur-find-buffer-matching.

diff --git a/ioccur.el b/ioccur.el
index d51e5c5..cf93d5a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -294,7 +294,7 @@ Hitting C-g in the buffer completion list will jump back to 
initial buffer."
                                     (car ioccur-history)
                                     '(ioccur-history . 1)))))
 
-  (let ((prompt   (format "Search in Buffer(%s): " regexp))
+  (let ((prompt   (format "Search (%s) in Buffer: " regexp))
         (buf-list (if current-prefix-arg
                       (ioccur-list-buffers-matching
                        (read-string "In Buffer matching: ") regexp)

commit 9a3e6f354c516b8d7ce69f173b524b55f14e6d67
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 27 17:34:23 2010 +0200

    Allow to select buffers by regexp in ioccur-find-buffer-matching.
    
    (ioccur-list-buffers-matching/containing) new.
    (ioccur-find-buffer-matching) Use a prefix arg.

diff --git a/ioccur.el b/ioccur.el
index 53453c1..d51e5c5 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -260,8 +260,21 @@ COLUMNS default value is `ioccur-length-line'."
       (goto-char (point-min))
       (when (re-search-forward regexp nil t) buffer))))
 
-(defun ioccur-buffers-matching (regexp)
-  "Return a list of all existing buffers containing REGEXP."
+(defun ioccur-list-buffers-matching (buffer-match regexp)
+  "Return a list of all buffer with name matching BUFFER-NAME and\
+containing lines matching REGEXP."
+  (loop
+     with ini-buf-list = (loop for buf in (buffer-list)
+                            unless (rassq buf dired-buffers)
+                            collect buf)
+     for buf in ini-buf-list
+     for bname = (buffer-name buf)
+     when (and (string-match buffer-match bname)
+               (ioccur-buffer-contain regexp buf))
+     collect bname))
+
+(defun ioccur-list-buffers-containing (regexp)
+  "Return a list of all existing buffers containing lines matching REGEXP."
   (loop with buf-list = (loop for i in (buffer-list)
                            when (buffer-file-name (get-buffer i))
                            collect i)
@@ -273,15 +286,19 @@ COLUMNS default value is `ioccur-length-line'."
 (defun* ioccur-find-buffer-matching (regexp)
   "Find an existing buffer containing an expression matching REGEXP\
 and connect `ioccur' to it.
-Hitting C-g in a `ioccur' search will return to buffer completion list.
+With a prefix arg search in buffer matching specified expression.
+Hitting C-g in a `ioccur' session will return to buffer completion list.
 Hitting C-g in the buffer completion list will jump back to initial buffer."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
-                       (read-string "Pattern: "
+                       (read-string "Search for Pattern: "
                                     (car ioccur-history)
                                     '(ioccur-history . 1)))))
 
-  (let ((prompt   (format "Search Buffer matching %s: " regexp))
-        (buf-list (ioccur-buffers-matching regexp))
+  (let ((prompt   (format "Search in Buffer(%s): " regexp))
+        (buf-list (if current-prefix-arg
+                      (ioccur-list-buffers-matching
+                       (read-string "In Buffer matching: ") regexp)
+                      (ioccur-list-buffers-containing regexp)))
         (win-conf (current-window-configuration)))
 
     (labels

commit 51280e45894cd3b25b0087e5917eba081d387830
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 27 16:19:55 2010 +0200

    (ioccur-find-buffer-matching) Add ido to possible completing-read functions.

diff --git a/ioccur.el b/ioccur.el
index 3a7e0a9..53453c1 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -286,9 +286,11 @@ Hitting C-g in the buffer completion list will jump back 
to initial buffer."
 
     (labels
         ((find-buffer ()
-           (let ((buf (if (fboundp 'anything-comp-read)
-                          (anything-comp-read prompt buf-list :must-match t)
-                          (completing-read prompt buf-list nil t))))
+           (let ((buf (cond ((fboundp 'anything-comp-read)
+                             (anything-comp-read prompt buf-list :must-match 
t))
+                            (ido-mode
+                             (ido-completing-read prompt buf-list nil t))
+                            (t (completing-read prompt buf-list nil t)))))
              (unwind-protect
                   (progn
                     (switch-to-buffer buf)

commit 9bc68cb51e2d99dc98782e7a5545e12531423157
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 27 09:06:29 2010 +0200

    (ioccur-find-buffer-matching) Retrieve initial window config when exiting 
buffer list with C-g.

diff --git a/ioccur.el b/ioccur.el
index 9f78fba..3a7e0a9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -140,7 +140,7 @@ Set it to nil to remove doc in mode-line."
 (defvar ioccur-count-occurences 0)
 (defvar ioccur-buffer nil)
 (make-variable-buffer-local 'ioccur-buffer)
-(defvar ioccur-success nil)  
+(defvar ioccur-success nil)
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -254,14 +254,14 @@ COLUMNS default value is `ioccur-length-line'."
         (substring ltp 0 ioccur-length-line) ltp)))
 
 (defun ioccur-buffer-contain (regexp buffer)
-  "Return BUFFER if BUFFER contain an occurence of REGEXP."
+  "Return BUFFER if it contain an occurence of REGEXP."
   (with-current-buffer buffer
     (save-excursion
       (goto-char (point-min))
       (when (re-search-forward regexp nil t) buffer))))
 
 (defun ioccur-buffers-matching (regexp)
-  "Returns a list of all existing buffers matching REGEXP."
+  "Return a list of all existing buffers containing REGEXP."
   (loop with buf-list = (loop for i in (buffer-list)
                            when (buffer-file-name (get-buffer i))
                            collect i)
@@ -270,22 +270,36 @@ COLUMNS default value is `ioccur-length-line'."
      collect (buffer-name buf)))
 
 ;;;###autoload
-(defun ioccur-find-buffer-matching (regexp &optional buffers)
+(defun* ioccur-find-buffer-matching (regexp)
   "Find an existing buffer containing an expression matching REGEXP\
-and connect `ioccur' to it."
+and connect `ioccur' to it.
+Hitting C-g in a `ioccur' search will return to buffer completion list.
+Hitting C-g in the buffer completion list will jump back to initial buffer."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
                        (read-string "Pattern: "
                                     (car ioccur-history)
                                     '(ioccur-history . 1)))))
-  (let* ((prompt   (format "Search Buffer matching %s: " regexp))
-         (buf-list (or buffers (ioccur-buffers-matching regexp)))
-         (buf      (if (fboundp 'anything-comp-read)
-                       (anything-comp-read prompt buf-list :must-match t)
-                       (completing-read prompt buf-list nil t))))
-    (switch-to-buffer buf)
-    (ioccur regexp)
-    (unless ioccur-success
-      (ioccur-find-buffer-matching regexp buf-list))))
+
+  (let ((prompt   (format "Search Buffer matching %s: " regexp))
+        (buf-list (ioccur-buffers-matching regexp))
+        (win-conf (current-window-configuration)))
+
+    (labels
+        ((find-buffer ()
+           (let ((buf (if (fboundp 'anything-comp-read)
+                          (anything-comp-read prompt buf-list :must-match t)
+                          (completing-read prompt buf-list nil t))))
+             (unwind-protect
+                  (progn
+                    (switch-to-buffer buf)
+                    (ioccur regexp)
+                    (unless ioccur-success
+                      (find-buffer)))
+               (unless ioccur-success
+                 (set-window-configuration win-conf)
+                 (return-from ioccur-find-buffer-matching))))))
+
+      (find-buffer))))
 
 ;;;###autoload
 (defun ioccur-restart ()

commit 2bc02dd72e75851ed9041035619be325b952eec7
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 26 10:52:18 2010 +0200

    (ioccur-find-buffer-matching) change confusing arg name.

diff --git a/ioccur.el b/ioccur.el
index 7502010..9f78fba 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -270,7 +270,7 @@ COLUMNS default value is `ioccur-length-line'."
      collect (buffer-name buf)))
 
 ;;;###autoload
-(defun ioccur-find-buffer-matching (regexp &optional buffer-list)
+(defun ioccur-find-buffer-matching (regexp &optional buffers)
   "Find an existing buffer containing an expression matching REGEXP\
 and connect `ioccur' to it."
   (interactive (list (let ((savehist-save-minibuffer-history nil))
@@ -278,7 +278,7 @@ and connect `ioccur' to it."
                                     (car ioccur-history)
                                     '(ioccur-history . 1)))))
   (let* ((prompt   (format "Search Buffer matching %s: " regexp))
-         (buf-list (or buffer-list (ioccur-buffers-matching regexp)))
+         (buf-list (or buffers (ioccur-buffers-matching regexp)))
          (buf      (if (fboundp 'anything-comp-read)
                        (anything-comp-read prompt buf-list :must-match t)
                        (completing-read prompt buf-list nil t))))

commit 3b3d4870252258b85b993522e7824c726436d83e
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 26 08:34:18 2010 +0200

    (ioccur-success) New flag non--nil when search is finish and we jump to a 
buffer.
    (ioccur) Start an incremental search if initial-input arg is provided.
    (ioccur, ioccur-find-buffer-matching) Use ioccur-success.

diff --git a/ioccur.el b/ioccur.el
index 516965a..7502010 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -140,7 +140,7 @@ Set it to nil to remove doc in mode-line."
 (defvar ioccur-count-occurences 0)
 (defvar ioccur-buffer nil)
 (make-variable-buffer-local 'ioccur-buffer)
-  
+(defvar ioccur-success nil)  
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -284,8 +284,7 @@ and connect `ioccur' to it."
                        (completing-read prompt buf-list nil t))))
     (switch-to-buffer buf)
     (ioccur regexp)
-    (when (and (not (string= (car ioccur-history) regexp))
-               (string= regexp ioccur-search-pattern))
+    (unless ioccur-success
       (ioccur-find-buffer-matching regexp buf-list))))
 
 ;;;###autoload
@@ -631,11 +630,13 @@ When you quit incremental search with RET, see 
`ioccur-mode'
 for commands provided in the `ioccur-buffer'."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)
+  (setq ioccur-success nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
   (message "Fontifying buffer...Please wait it could be long.")
   (jit-lock-fontify-now) (message nil)
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
-  (if (and (get-buffer ioccur-buffer)
+  (if (and (not initial-input)
+           (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
       ;; An hidden `ioccur-buffer' exists jump to it.
       (pop-to-buffer ioccur-buffer t)
@@ -668,7 +669,8 @@ for commands provided in the `ioccur-buffer'."
                    (switch-to-buffer ioccur-current-buffer)
                    (when ioccur-match-overlay
                      (delete-overlay ioccur-match-overlay))
-                   (delete-other-windows) (goto-char curpos) (message nil))
+                   (delete-other-windows) (goto-char curpos)
+                   (message nil))
                   (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
                    (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
                    (message nil) (ioccur-save-history))
@@ -694,7 +696,8 @@ for commands provided in the `ioccur-buffer'."
             ioccur-history)))
   (when (> (length ioccur-history) ioccur-max-length-history)
     (setq ioccur-history (delete (car (last ioccur-history))
-                                 ioccur-history))))
+                                 ioccur-history)))
+  (setq ioccur-success t))
 
 (defun ioccur-cancel-search ()
   "Cancel timer used for ioccur searching."

commit 545dc86cdeca1e56ec42c538be6784e6b26f9c37
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 25 22:50:03 2010 +0200

    (ioccur-find-buffer-matching) Don't save ioccur-history from read-string in 
minibuffer history.

diff --git a/ioccur.el b/ioccur.el
index 11b9d84..516965a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -273,9 +273,10 @@ COLUMNS default value is `ioccur-length-line'."
 (defun ioccur-find-buffer-matching (regexp &optional buffer-list)
   "Find an existing buffer containing an expression matching REGEXP\
 and connect `ioccur' to it."
-  (interactive (list (read-string "Pattern: "
-                                  (car ioccur-history)
-                                  '(ioccur-history . 1))))
+  (interactive (list (let ((savehist-save-minibuffer-history nil))
+                       (read-string "Pattern: "
+                                    (car ioccur-history)
+                                    '(ioccur-history . 1)))))
   (let* ((prompt   (format "Search Buffer matching %s: " regexp))
          (buf-list (or buffer-list (ioccur-buffers-matching regexp)))
          (buf      (if (fboundp 'anything-comp-read)

commit 3593302203b5663c5b87995bc067850aa5e83f66
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 25 22:36:21 2010 +0200

    (ioccur-find-buffer-matching) add default-input and bind ioccur-history to 
read-string

diff --git a/ioccur.el b/ioccur.el
index a18123e..11b9d84 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -273,7 +273,9 @@ COLUMNS default value is `ioccur-length-line'."
 (defun ioccur-find-buffer-matching (regexp &optional buffer-list)
   "Find an existing buffer containing an expression matching REGEXP\
 and connect `ioccur' to it."
-  (interactive "sPattern: ")
+  (interactive (list (read-string "Pattern: "
+                                  (car ioccur-history)
+                                  '(ioccur-history . 1))))
   (let* ((prompt   (format "Search Buffer matching %s: " regexp))
          (buf-list (or buffer-list (ioccur-buffers-matching regexp)))
          (buf      (if (fboundp 'anything-comp-read)

commit 5d13a8787e92dca88099376ef403068988d95d5b
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 25 22:15:50 2010 +0200

    (ioccur-find-buffer-matching) Replace now unuseful while by when.

diff --git a/ioccur.el b/ioccur.el
index 0a68ab0..a18123e 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -281,8 +281,8 @@ and connect `ioccur' to it."
                        (completing-read prompt buf-list nil t))))
     (switch-to-buffer buf)
     (ioccur regexp)
-    (while (and (not (string= (car ioccur-history) regexp))
-                (string= regexp ioccur-search-pattern))
+    (when (and (not (string= (car ioccur-history) regexp))
+               (string= regexp ioccur-search-pattern))
       (ioccur-find-buffer-matching regexp buf-list))))
 
 ;;;###autoload

commit 8c00d3f93913e2cdff6d6d8d0fd40718f5ec5da2
Author: Thierry Volpiatto <address@hidden>
Date:   Tue May 25 11:32:20 2010 +0200

    (ioccur-find-buffer-matching) Recurse until jumping to 
ioccur-current-buffer or pattern change.

diff --git a/ioccur.el b/ioccur.el
index 953ffe4..0a68ab0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -270,17 +270,20 @@ COLUMNS default value is `ioccur-length-line'."
      collect (buffer-name buf)))
 
 ;;;###autoload
-(defun ioccur-find-buffer-matching (regexp)
+(defun ioccur-find-buffer-matching (regexp &optional buffer-list)
   "Find an existing buffer containing an expression matching REGEXP\
 and connect `ioccur' to it."
   (interactive "sPattern: ")
   (let* ((prompt   (format "Search Buffer matching %s: " regexp))
-         (buf-list (ioccur-buffers-matching regexp))
+         (buf-list (or buffer-list (ioccur-buffers-matching regexp)))
          (buf      (if (fboundp 'anything-comp-read)
                        (anything-comp-read prompt buf-list :must-match t)
                        (completing-read prompt buf-list nil t))))
     (switch-to-buffer buf)
-    (ioccur regexp)))
+    (ioccur regexp)
+    (while (and (not (string= (car ioccur-history) regexp))
+                (string= regexp ioccur-search-pattern))
+      (ioccur-find-buffer-matching regexp buf-list))))
 
 ;;;###autoload
 (defun ioccur-restart ()

commit 4531cbcaf96f5c0b234d079bdd95bdf5aa77b7cd
Author: Thierry Volpiatto <address@hidden>
Date:   Mon May 24 20:19:15 2010 +0200

    (ioccur-buffer-contain) Don't use return-from

diff --git a/ioccur.el b/ioccur.el
index 265d921..953ffe4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -253,28 +253,27 @@ COLUMNS default value is `ioccur-length-line'."
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
-(defun* ioccur-buffer-contain (regexp buffer)
+(defun ioccur-buffer-contain (regexp buffer)
   "Return BUFFER if BUFFER contain an occurence of REGEXP."
   (with-current-buffer buffer
     (save-excursion
       (goto-char (point-min))
-      (when (re-search-forward regexp nil t)
-        (return-from ioccur-buffer-contain buffer)))))
+      (when (re-search-forward regexp nil t) buffer))))
 
 (defun ioccur-buffers-matching (regexp)
   "Returns a list of all existing buffers matching REGEXP."
-  (loop with buf-list = (loop
-                           for i in (buffer-list)
-                           when (buffer-file-name
-                                 (get-buffer i)) collect i)
+  (loop with buf-list = (loop for i in (buffer-list)
+                           when (buffer-file-name (get-buffer i))
+                           collect i)
      for buf in buf-list
      when (ioccur-buffer-contain regexp buf)
      collect (buffer-name buf)))
 
 ;;;###autoload
 (defun ioccur-find-buffer-matching (regexp)
-  "Find an existing buffer matching REGEXP and connect `ioccur' to it."
-  (interactive "sRegexp: ")
+  "Find an existing buffer containing an expression matching REGEXP\
+and connect `ioccur' to it."
+  (interactive "sPattern: ")
   (let* ((prompt   (format "Search Buffer matching %s: " regexp))
          (buf-list (ioccur-buffers-matching regexp))
          (buf      (if (fboundp 'anything-comp-read)

commit 5ae17c1e63db91e3a0e3c865c69eb84686e01a0c
Author: Thierry Volpiatto <address@hidden>
Date:   Mon May 24 18:07:54 2010 +0200

    New ioccur-find-buffer-matching allow to match all buffers matching regexp 
in buffer-list.
    
    (ioccur-buffer-contain, ioccur-buffers-matching, 
ioccur-find-buffer-matching) New.

diff --git a/ioccur.el b/ioccur.el
index dcdfb3b..265d921 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -253,6 +253,36 @@ COLUMNS default value is `ioccur-length-line'."
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
+(defun* ioccur-buffer-contain (regexp buffer)
+  "Return BUFFER if BUFFER contain an occurence of REGEXP."
+  (with-current-buffer buffer
+    (save-excursion
+      (goto-char (point-min))
+      (when (re-search-forward regexp nil t)
+        (return-from ioccur-buffer-contain buffer)))))
+
+(defun ioccur-buffers-matching (regexp)
+  "Returns a list of all existing buffers matching REGEXP."
+  (loop with buf-list = (loop
+                           for i in (buffer-list)
+                           when (buffer-file-name
+                                 (get-buffer i)) collect i)
+     for buf in buf-list
+     when (ioccur-buffer-contain regexp buf)
+     collect (buffer-name buf)))
+
+;;;###autoload
+(defun ioccur-find-buffer-matching (regexp)
+  "Find an existing buffer matching REGEXP and connect `ioccur' to it."
+  (interactive "sRegexp: ")
+  (let* ((prompt   (format "Search Buffer matching %s: " regexp))
+         (buf-list (ioccur-buffers-matching regexp))
+         (buf      (if (fboundp 'anything-comp-read)
+                       (anything-comp-read prompt buf-list :must-match t)
+                       (completing-read prompt buf-list nil t))))
+    (switch-to-buffer buf)
+    (ioccur regexp)))
+
 ;;;###autoload
 (defun ioccur-restart ()
   "Restart `ioccur' from `ioccur-buffer'.
@@ -605,7 +635,11 @@ for commands provided in the `ioccur-buffer'."
       ;; An hidden `ioccur-buffer' exists jump to it.
       (pop-to-buffer ioccur-buffer t)
       ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
-      (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
+      (let* ((init-str (if initial-input
+                           (if (stringp initial-input)
+                               initial-input
+                               (thing-at-point 'symbol))
+                           ""))
              (len      (length init-str))
              (curpos   (point))
              str-no-prop)

commit 3ea3a84c90496ce7496dec749a663be40d5a1d83
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 21 22:26:13 2010 +0200

    (ioccur-print-results) Remove optional arg.
    (ioccur-print-line) Remove optional arg.

diff --git a/ioccur.el b/ioccur.el
index 8d905e5..dcdfb3b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -212,11 +212,11 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defun* ioccur-print-results (regexp &optional (buffer ioccur-current-buffer))
+(defun ioccur-print-results (regexp)
   "Print in `ioccur-buffer' all lines matching REGEXP found in BUFFER.
 BUFFER default value is `ioccur-current-buffer'."
   (setq ioccur-count-occurences 0)
-  (with-current-buffer buffer
+  (with-current-buffer ioccur-current-buffer
     (save-excursion
       (goto-char (point-min))
       (loop
@@ -232,7 +232,7 @@ BUFFER default value is `ioccur-current-buffer'."
              (buffer-substring (point-at-bol) (point-at-eol)) count)
          do (forward-line 1)))))
 
-(defun* ioccur-print-line (line nline &optional (buffer ioccur-buffer))
+(defun ioccur-print-line (line nline)
   "Prepare and insert a matched LINE at line number NLINE in BUFFER.
 BUFFER default value is `ioccur-buffer'."
   (with-current-buffer ioccur-buffer

commit 334a46458e75b3979a1a4fc4d7442ee022a40dab
Merge: 7abb893 74392eb
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 20 15:26:45 2010 +0200

    Merge tags in dev.


commit 7abb893404d8d8dd4da89a475d11ed96d3d9a969
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 20 15:25:58 2010 +0200

    Added tag V-1.5 for changeset 8afc7427fa57

commit 10946613edebb3605b913fb4101a7c28a022606c
Merge: 74392eb 1d7d45f
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 20 15:25:30 2010 +0200

    Merge branchs


commit 74392eb0bf80525a9d38f13e8583ee049afbde37
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 20 09:51:06 2010 +0200

    Add optional arguments to reuse functions elsewhere.
    
    (ioccur-print-results, ioccur-print-line) add optional arg buffer.
    (ioccur-truncate-line) add optional arg columns

diff --git a/ioccur.el b/ioccur.el
index 542e0a4..8d905e5 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -212,11 +212,11 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defun ioccur-print-results (regexp)
-  "Print in `ioccur-buffer' all lines matching REGEXP \
-found in `ioccur-current-buffer'."
+(defun* ioccur-print-results (regexp &optional (buffer ioccur-current-buffer))
+  "Print in `ioccur-buffer' all lines matching REGEXP found in BUFFER.
+BUFFER default value is `ioccur-current-buffer'."
   (setq ioccur-count-occurences 0)
-  (with-current-buffer ioccur-current-buffer
+  (with-current-buffer buffer
     (save-excursion
       (goto-char (point-min))
       (loop
@@ -232,8 +232,9 @@ found in `ioccur-current-buffer'."
              (buffer-substring (point-at-bol) (point-at-eol)) count)
          do (forward-line 1)))))
 
-(defun ioccur-print-line (line nline)
-  "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
+(defun* ioccur-print-line (line nline &optional (buffer ioccur-buffer))
+  "Prepare and insert a matched LINE at line number NLINE in BUFFER.
+BUFFER default value is `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let ((lineno     (int-to-string (1+ nline)))
           (trunc-line (ioccur-truncate-line line)))
@@ -243,8 +244,9 @@ found in `ioccur-current-buffer'."
                    'help-echo line)
               ":" trunc-line "\n"))))
 
-(defun ioccur-truncate-line (line)
-  "Remove indentation and truncate LINE to `ioccur-length-line'."
+(defun* ioccur-truncate-line (line &optional (columns ioccur-length-line))
+  "Remove indentation and truncate LINE to COLUMNS.
+COLUMNS default value is `ioccur-length-line'."
   (let* ((bol-reg (if (string-match "^\t" line)
                       "\\(^\t*\\)" "\\(^ *\\)"))
          (ltp     (replace-regexp-in-string bol-reg "" line)))
@@ -529,7 +531,7 @@ START-POINT is the point where we start searching in 
buffer."
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
 
 (defun ioccur-print-buffer (regexp)
-  "Prepare and print results in `ioccur-buffer'."
+  "Pretty Print results matching REGEXP in `ioccur-buffer'."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))

commit 2a59ce05bd0a86db1911f07adb942f10b8540614
Author: Chris Wanstrath <address@hidden>
Date:   Thu May 20 00:37:20 2010 -0700

    c'mon

diff --git a/README.md b/README.md
index 570219c..5df856a 100644
--- a/README.md
+++ b/README.md
@@ -280,6 +280,7 @@ Default: `"*coffee-compiled*"`
 
 ## Thanks
 
+* Jeremy Ashkenas for CoffeeScript
 * <http://xahlee.org/emacs/elisp_syntax_coloring.html> for instructions.
 * Jason Blevins for the guidance his markdown-mode.el gave.
 * Steve Yegge for js2

commit 0cb906be583e1c3d1f20cfba2cd09412fcd65a1d
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 20 09:25:06 2010 +0200

    Keep fixing comments, no code changes.

diff --git a/ioccur.el b/ioccur.el
index a506c2b..542e0a4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -503,7 +503,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (with-current-buffer ioccur-current-buffer
                     ;; Start to initial point if C-w have never been hit.
                     (unless yank-point (setq yank-point old-yank-point))
-                    ;; After a search `ioccur-find-readlines' have put point
+                    ;; After a search `ioccur-print-results' have put point
                     ;; to point-max, so reset position.
                     (when yank-point (goto-char yank-point))
                     (forward-word 1)
@@ -602,8 +602,7 @@ for commands provided in the `ioccur-buffer'."
            (not (get-buffer-window ioccur-buffer)))
       ;; An hidden `ioccur-buffer' exists jump to it.
       (pop-to-buffer ioccur-buffer t)
-      ;; `ioccur-buffer' doesn't exists or is not visible
-      ;; Start incremental search.
+      ;; `ioccur-buffer' doesn't exists or is not visible, start searching.
       (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
              (len      (length init-str))
              (curpos   (point))

commit 840cef17f97db7986b317f487bc3c7789b4aac0a
Author: Thierry Volpiatto <address@hidden>
Date:   Mon May 17 14:06:57 2010 +0200

    No code change, only comments.

diff --git a/ioccur.el b/ioccur.el
index a26c12c..a506c2b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -399,6 +399,7 @@ START-POINT is the point where we start searching in 
buffer."
     ;; Cycle history function.
     ;;
     (flet ((cycle-hist (arg)
+             ;; ARG can be positive or negative depending we call M-p or M-n.
              (if ioccur-history
                  (progn
                    ;; Cycle history will start at second call,
@@ -406,7 +407,7 @@ START-POINT is the point where we start searching in 
buffer."
                    ;; We build a new iterator based on a sublist
                    ;; starting at the current element of history.
                    ;; This is a circular iterator. (no end)
-                   (if start-hist ; At first call start-hist is nil.
+                   (if start-hist ; At first call, start-hist is nil.
                        (progn
                          (if (< arg 0)
                              ;; M-p (move from left to right in hist ring).

commit ab8320d895cc59dcbbf53fa11612eb791db3a704
Author: Thierry Volpiatto <address@hidden>
Date:   Sun May 16 10:36:56 2010 +0200

    (ioccur-print-buffer) Take only one arg, fix docstring.

diff --git a/ioccur.el b/ioccur.el
index be56799..a26c12c 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -527,8 +527,8 @@ START-POINT is the point where we start searching in 
buffer."
                       nil))))
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
 
-(defun ioccur-print-buffer (regexp buffer-name)
-  "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
+(defun ioccur-print-buffer (regexp)
+  "Prepare and print results in `ioccur-buffer'."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
         (progn (erase-buffer) (insert title "\n\n"))
@@ -541,7 +541,7 @@ START-POINT is the point where we start searching in 
buffer."
                             'face 'underline)
                 (propertize regexp 'face 'ioccur-regexp-face)
                 (propertize
-                 (format " in %s" buffer-name)
+                 (format " in %s" ioccur-current-buffer)
                  'face 'underline) "\n\n")
         (ioccur-color-current-line))))
 
@@ -552,9 +552,8 @@ START-POINT is the point where we start searching in 
buffer."
          ioccur-search-delay 'repeat
          #'(lambda ()
              (ioccur-print-buffer
-              ioccur-search-pattern
-              ioccur-current-buffer)))))
-
+              ioccur-search-pattern)))))
+              
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.

commit fc3a04984b7c93afd28d003079f2571085ab11b9
Author: Thierry Volpiatto <address@hidden>
Date:   Sun May 16 07:52:59 2010 +0200

    Minor changes, remove one concat and fix docstring.
    
    (ioccur-print-buffer) Remove one unuseful concat.
    (ioccur-print-results) Fix docstring.

diff --git a/ioccur.el b/ioccur.el
index e05b971..be56799 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -213,7 +213,8 @@ Special commands:
                    (ioccur-iter-next iterator)))))))
 
 (defun ioccur-print-results (regexp)
-  "Print all lines matching REGEXP in `ioccur-buffer'."
+  "Print in `ioccur-buffer' all lines matching REGEXP \
+found in `ioccur-current-buffer'."
   (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
     (save-excursion
@@ -530,7 +531,7 @@ START-POINT is the point where we start searching in 
buffer."
   "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
-        (progn (erase-buffer) (insert (concat title "\n\n")))
+        (progn (erase-buffer) (insert title "\n\n"))
         (erase-buffer)
         (ioccur-print-results regexp)
         (goto-char (point-min))

commit 28b6e31e76e29832bc41db28e4aa764f52f09b19
Author: Thierry Volpiatto <address@hidden>
Date:   Sat May 15 19:21:25 2010 +0200

    (ioccur-print-results) Even faster beat precedent version of nearly 2 
seconds and occur 14 seconds!

diff --git a/ioccur.el b/ioccur.el
index f31f834..e05b971 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -226,9 +226,9 @@ Special commands:
          ;; and we have no chance to exit loop.
          when quit-flag do (setq ioccur-quit-flag t) and return nil
          for count from 0
-         for line = (buffer-substring (point-at-bol) (point-at-eol))
-         when (string-match regexp line)
-         do (ioccur-print-line line count)
+         when (re-search-forward regexp (point-at-eol) t)
+         do (ioccur-print-line
+             (buffer-substring (point-at-bol) (point-at-eol)) count)
          do (forward-line 1)))))
 
 (defun ioccur-print-line (line nline)

commit 2426cd1990acbacf19292e4589cf4fddb165d33c
Merge: af0da34 1d7d45f
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 12:32:28 2010 +0200

    Merge tags.


commit 1d7d45f85ae189d166ba06e9ba81caf0f3a52374
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 12:31:19 2010 +0200

    Added tag V-1.4 for changeset 202622367ad4

commit b9ae27edf8b79b8322d1f8fa0a5487185caa3cf2
Merge: a9bd319 af0da34
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 12:30:10 2010 +0200

    Merge branchs.


commit af0da34870440d38c6770264a1afd51dbb40c274
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 12:24:04 2010 +0200

    No code change, only reorder and reindent.

diff --git a/ioccur.el b/ioccur.el
index 8bc4407..f31f834 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -245,7 +245,7 @@ Special commands:
 (defun ioccur-truncate-line (line)
   "Remove indentation and truncate LINE to `ioccur-length-line'."
   (let* ((bol-reg (if (string-match "^\t" line)
-                           "\\(^\t*\\)" "\\(^ *\\)"))
+                      "\\(^\t*\\)" "\\(^ *\\)"))
          (ltp     (replace-regexp-in-string bol-reg "" line)))
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
@@ -255,10 +255,8 @@ Special commands:
   "Restart `ioccur' from `ioccur-buffer'.
 `ioccur-buffer' is erased and a new search is started."
   (interactive)
-  (when (and (eq major-mode 'ioccur-mode)
-             (eq (count-windows) 2))
-    (other-window 1)
-    (ioccur)))
+  (when (and (eq major-mode 'ioccur-mode) (eq (count-windows) 2))
+    (other-window 1) (ioccur)))
 
 ;;;###autoload
 (defun ioccur-quit ()
@@ -466,8 +464,7 @@ START-POINT is the point where we start searching in 
buffer."
                   (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
                  ((?\C-d C-down)                ; Scroll both windows down.
-                  (stop-timer)
-                  (ioccur-scroll-down) t)
+                  (stop-timer) (ioccur-scroll-down) t)
                  ((?\C-u C-up)                  ; Scroll both windows up.
                   (stop-timer) (ioccur-scroll-up) t)
                  (?\r                           ; RET break and exit code.

commit b566bc3e1f4c5b2aa3d1376e0982e71781260e10
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 08:49:03 2010 +0200

    (ioccur-print-results) Set ioccur-quit-flag when exiting from here to 
inform ioccur we are quitting.

diff --git a/ioccur.el b/ioccur.el
index dc2711b..8bc4407 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -213,7 +213,7 @@ Special commands:
                    (ioccur-iter-next iterator)))))))
 
 (defun ioccur-print-results (regexp)
-  "Print al lines matching REGEXP in `ioccur-buffer'."
+  "Print all lines matching REGEXP in `ioccur-buffer'."
   (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
     (save-excursion
@@ -224,7 +224,7 @@ Special commands:
          ;; Because when loop is started `ioccur-read-search-input'
          ;; will read key only when loop is finished
          ;; and we have no chance to exit loop.
-         when quit-flag return nil
+         when quit-flag do (setq ioccur-quit-flag t) and return nil
          for count from 0
          for line = (buffer-substring (point-at-bol) (point-at-eol))
          when (string-match regexp line)
@@ -232,7 +232,7 @@ Special commands:
          do (forward-line 1)))))
 
 (defun ioccur-print-line (line nline)
-  "Prepare and insert a matched line in `ioccur-buffer'."
+  "Prepare and insert a matched LINE at line number NLINE in `ioccur-buffer'."
   (with-current-buffer ioccur-buffer
     (let ((lineno     (int-to-string (1+ nline)))
           (trunc-line (ioccur-truncate-line line)))

commit cbe7dd2581bd76f09f1431857bd22beb1ed55e96
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 14 07:59:57 2010 +0200

    Get rid of ioccur-find-readlines, much much faster now.
    
    (ioccur-find-readlines) Removed
    (ioccur-print-results) Print line at each time is found instead of storing.
    (ioccur-print-line) new

diff --git a/ioccur.el b/ioccur.el
index e29ac9b..dc2711b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -212,8 +212,9 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defun ioccur-find-readlines (regexp)
-  "Return a vector of all \(numline line\) matching REGEXP."
+(defun ioccur-print-results (regexp)
+  "Print al lines matching REGEXP in `ioccur-buffer'."
+  (setq ioccur-count-occurences 0)
   (with-current-buffer ioccur-current-buffer
     (save-excursion
       (goto-char (point-min))
@@ -227,9 +228,19 @@ Special commands:
          for count from 0
          for line = (buffer-substring (point-at-bol) (point-at-eol))
          when (string-match regexp line)
-         vconcat (list (list count line)) into vec
-         do (forward-line 1)
-         finally return vec))))
+         do (ioccur-print-line line count)
+         do (forward-line 1)))))
+
+(defun ioccur-print-line (line nline)
+  "Prepare and insert a matched line in `ioccur-buffer'."
+  (with-current-buffer ioccur-buffer
+    (let ((lineno     (int-to-string (1+ nline)))
+          (trunc-line (ioccur-truncate-line line)))
+      (incf ioccur-count-occurences)
+      (insert " " (propertize
+                   lineno 'face 'ioccur-num-line-face
+                   'help-echo line)
+              ":" trunc-line "\n"))))
 
 (defun ioccur-truncate-line (line)
   "Remove indentation and truncate LINE to `ioccur-length-line'."
@@ -239,24 +250,6 @@ Special commands:
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
-(defun ioccur-print-results (regex)
-  "Print lines matching REGEX in `ioccur-buffer'."
-  (setq ioccur-count-occurences 0)
-  (let ((matched-lines (ioccur-find-readlines regex)))
-    (when matched-lines
-      (loop for i across matched-lines
-         for line        = (second i)
-         for lineno      = (int-to-string (1+ (first i)))
-         for trunc-line  = (ioccur-truncate-line line)
-         do
-           (progn
-             (incf ioccur-count-occurences)
-             (insert " "
-                     (propertize
-                      lineno 'face 'ioccur-num-line-face
-                      'help-echo line)
-                     ":" trunc-line "\n"))))))
-
 ;;;###autoload
 (defun ioccur-restart ()
   "Restart `ioccur' from `ioccur-buffer'.

commit 98f8e878aedbb5ec8d2ec0264010119dc2db2c41
Author: Thierry Volpiatto <address@hidden>
Date:   Thu May 13 08:35:17 2010 +0200

    No code change, refactoring.

diff --git a/ioccur.el b/ioccur.el
index fea3091..e29ac9b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -8,7 +8,7 @@
 
 ;; X-URL: http://mercurial.intuxication.org/hg/ioccur
 
-;; This file is not part of GNU Emacs. 
+;; This file is not part of GNU Emacs.
 
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -26,12 +26,16 @@
 ;; Floor, Boston, MA 02110-1301, USA.
 
 ;;; Install:
-;;  -------
-
+;;
 ;; Add this file to your `load-path', BYTE-COMPILE it and
 ;; add (require 'ioccur) in your .emacs.
 ;; Start with M-x ioccur
 
+;;; Commentary:
+;;
+;; You may want to save `ioccur-history', you can do that if you
+;; use desktop, adding that to your .emacs:
+;; (add-to-list 'desktop-globals-to-save 'ioccur-history)
 
 ;;; Code:
 (require 'derived)
@@ -229,14 +233,14 @@ Special commands:
 
 (defun ioccur-truncate-line (line)
   "Remove indentation and truncate LINE to `ioccur-length-line'."
-  (let* ((bol-reg      (if (string-match "^\t" line)
+  (let* ((bol-reg (if (string-match "^\t" line)
                            "\\(^\t*\\)" "\\(^ *\\)"))
-         (ltp         (replace-regexp-in-string bol-reg "" line)))
+         (ltp     (replace-regexp-in-string bol-reg "" line)))
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
 (defun ioccur-print-results (regex)
-  "Print matched lines in ioccur buffer."
+  "Print lines matching REGEX in `ioccur-buffer'."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines regex)))
     (when matched-lines
@@ -274,11 +278,12 @@ Special commands:
   (delete-other-windows))
 
 (defun ioccur-goto-line (numline)
-  "Non--interactive version of `goto-line.'"
+  "Non--interactive version of `goto-line.'.
+Goto NUMLINE."
   (goto-char (point-min)) (forward-line (1- numline)))
 
 (defun ioccur-forward-line (n)
-  "Forward line only if it is not an empty line."
+  "Forward N lines but empty one's."
   (let (pos)
     (save-excursion
       (forward-line n) (forward-line 0)
@@ -342,7 +347,7 @@ Move point to first occurence of `ioccur-search-pattern'."
   (scroll-other-window -1))
 
 (defun ioccur-scroll (n)
-  "Scroll other buffer and move overlay accordingly."
+  "Scroll other buffer N lines and move overlay accordingly."
   (ioccur-forward-line n)
   (ioccur-color-current-line)
   (when (ioccur-jump)
@@ -374,7 +379,7 @@ Move point to first occurence of `ioccur-search-pattern'."
        (get-buffer ioccur-buffer)))))
 
 (defun ioccur-read-char-or-event (prompt)
-  "Replace `read-key' when  not available."
+  "Replace `read-key' when not available using PROMPT."
   (if (fboundp 'read-key)
       (read-key prompt)
       (let* ((chr (condition-case nil (read-char prompt) (error nil)))
@@ -382,7 +387,9 @@ Move point to first occurence of `ioccur-search-pattern'."
         (or chr evt))))
 
 (defun ioccur-read-search-input (initial-input start-point)
-  "Read each keyboard input and add it to `ioccur-search-pattern'."
+  "Read each keyboard input and add it to `ioccur-search-pattern'.
+INITIAL-INPUT is a string given as default input, generally thing at point.
+START-POINT is the point where we start searching in buffer."
   (let* ((prompt         (propertize ioccur-search-prompt
                                      'face 'minibuffer-prompt))
          (inhibit-quit   (or (eq system-type 'windows-nt)
@@ -665,7 +672,7 @@ for commands provided in the `ioccur-buffer'."
     (setq ioccur-search-timer nil)))
 
 (defun ioccur-color-current-line ()
-  "Highlight and underline current line in ioccur buffer."
+  "Highlight and underline current line in `ioccur-buffer'."
   (if ioccur-occur-overlay
       (move-overlay ioccur-occur-overlay
                     (point-at-bol) (1+ (point-at-eol)) ioccur-buffer)
@@ -674,7 +681,8 @@ for commands provided in the `ioccur-buffer'."
   (overlay-put ioccur-occur-overlay 'face 'ioccur-overlay-face))
 
 (defun ioccur-color-matched-line ()
-  "Highlight and underline current position on matched line in current-buffer."
+  "Highlight and underline current position \
+of matched line in `ioccur-current-buffer'."
   (if ioccur-match-overlay
       (move-overlay ioccur-match-overlay
                     (point-at-bol) (1+ (point-at-eol)))
@@ -682,7 +690,7 @@ for commands provided in the `ioccur-buffer'."
             (make-overlay (point-at-bol) (1+ (point-at-eol)))))
   (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
-;;; Provide
+
 (provide 'ioccur)
 
-;;; ioccur.el ends here.
+;;; ioccur.el ends here

commit c0c53637678bfa6d43b584fcba00981c4d8bdbcf
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 12 22:09:30 2010 +0200

    Rename ioccur-update-buffer to *-print-buffer

diff --git a/ioccur.el b/ioccur.el
index 9a2fcff..fea3091 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -529,7 +529,7 @@ Move point to first occurence of `ioccur-search-pattern'."
                       nil))))
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
 
-(defun ioccur-update-buffer (regexp buffer-name)
+(defun ioccur-print-buffer (regexp buffer-name)
   "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
@@ -553,7 +553,7 @@ Move point to first occurence of `ioccur-search-pattern'."
         (run-with-idle-timer
          ioccur-search-delay 'repeat
          #'(lambda ()
-             (ioccur-update-buffer
+             (ioccur-print-buffer
               ioccur-search-pattern
               ioccur-current-buffer)))))
 

commit b0d84c743691f3b75d0f47de609b9e2791c44843
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 12 20:52:20 2010 +0200

    Rename ioccur-print-buffer to ioccur-print-results.

diff --git a/ioccur.el b/ioccur.el
index d014128..9a2fcff 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -235,7 +235,7 @@ Special commands:
     (if (> (length ltp) ioccur-length-line)
         (substring ltp 0 ioccur-length-line) ltp)))
 
-(defun ioccur-print-buffer (regex)
+(defun ioccur-print-results (regex)
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines regex)))
@@ -535,7 +535,7 @@ Move point to first occurence of `ioccur-search-pattern'."
     (if (string= regexp "")
         (progn (erase-buffer) (insert (concat title "\n\n")))
         (erase-buffer)
-        (ioccur-print-buffer regexp)
+        (ioccur-print-results regexp)
         (goto-char (point-min))
         (insert title "\n\n"
                 (propertize (format "Found %s occurences of "

commit a755942404c47f1a9341cc19593f7f46d00d8f2b
Author: Thierry Volpiatto <address@hidden>
Date:   Mon May 10 09:36:18 2010 +0200

    (ioccur-find-readlines) save-excursion

diff --git a/ioccur.el b/ioccur.el
index 2ba8210..d014128 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -211,20 +211,21 @@ Special commands:
 (defun ioccur-find-readlines (regexp)
   "Return a vector of all \(numline line\) matching REGEXP."
   (with-current-buffer ioccur-current-buffer
-    (goto-char (point-min))
-    (loop
-       while (not (eobp))
-       ;; We need to read also C-g from here
-       ;; Because when loop is started `ioccur-read-search-input'
-       ;; will read key only when loop is finished
-       ;; and we have no chance to exit loop.
-       when quit-flag return nil
-       for count from 0
-       for line = (buffer-substring (point-at-bol) (point-at-eol))
-       when (string-match regexp line)
-       vconcat (list (list count line)) into vec
-       do (forward-line 1)
-       finally return vec)))
+    (save-excursion
+      (goto-char (point-min))
+      (loop
+         while (not (eobp))
+         ;; We need to read also C-g from here
+         ;; Because when loop is started `ioccur-read-search-input'
+         ;; will read key only when loop is finished
+         ;; and we have no chance to exit loop.
+         when quit-flag return nil
+         for count from 0
+         for line = (buffer-substring (point-at-bol) (point-at-eol))
+         when (string-match regexp line)
+         vconcat (list (list count line)) into vec
+         do (forward-line 1)
+         finally return vec))))
 
 (defun ioccur-truncate-line (line)
   "Remove indentation and truncate LINE to `ioccur-length-line'."

commit f8c6d9a696b6d1e2280df6d57ab5797af515c6c8
Author: Thierry Volpiatto <address@hidden>
Date:   Mon May 10 09:21:41 2010 +0200

    Allow exiting from search loop, new func to truncate lines.
    
    (ioccur-find-readlines) Allow exiting from here
    (ioccur-print-buffer, ioccur-update-buffer) get rid of lline key.
    (ioccur-truncate-line) new

diff --git a/ioccur.el b/ioccur.el
index 60c74ab..2ba8210 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -208,12 +208,17 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defsubst ioccur-find-readlines (regexp)
-  "Return an alist of all the (numline line) matching REGEXP."
+(defun ioccur-find-readlines (regexp)
+  "Return a vector of all \(numline line\) matching REGEXP."
   (with-current-buffer ioccur-current-buffer
     (goto-char (point-min))
     (loop
        while (not (eobp))
+       ;; We need to read also C-g from here
+       ;; Because when loop is started `ioccur-read-search-input'
+       ;; will read key only when loop is finished
+       ;; and we have no chance to exit loop.
+       when quit-flag return nil
        for count from 0
        for line = (buffer-substring (point-at-bol) (point-at-eol))
        when (string-match regexp line)
@@ -221,25 +226,31 @@ Special commands:
        do (forward-line 1)
        finally return vec)))
 
-(defsubst* ioccur-print-buffer (regex &key (lline ioccur-length-line))
+(defun ioccur-truncate-line (line)
+  "Remove indentation and truncate LINE to `ioccur-length-line'."
+  (let* ((bol-reg      (if (string-match "^\t" line)
+                           "\\(^\t*\\)" "\\(^ *\\)"))
+         (ltp         (replace-regexp-in-string bol-reg "" line)))
+    (if (> (length ltp) ioccur-length-line)
+        (substring ltp 0 ioccur-length-line) ltp)))
+
+(defun ioccur-print-buffer (regex)
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines regex)))
     (when matched-lines
       (loop for i across matched-lines
          for line        = (second i)
-         for bol-reg     = (if (string-match "^\t" line)
-                               "\\(^\t*\\)" "\\(^ *\\)")
          for lineno      = (int-to-string (1+ (first i)))
-         for ltp         = (replace-regexp-in-string bol-reg "" line)
-         for trunc-line  = (if (> (length ltp) lline)
-                               (substring ltp 0 lline) ltp)
+         for trunc-line  = (ioccur-truncate-line line)
          do
            (progn
              (incf ioccur-count-occurences)
-             (insert (concat " " (propertize lineno 'face 'ioccur-num-line-face
-                                             'help-echo ltp)
-                             ":" trunc-line "\n")))))))
+             (insert " "
+                     (propertize
+                      lineno 'face 'ioccur-num-line-face
+                      'help-echo line)
+                     ":" trunc-line "\n"))))))
 
 ;;;###autoload
 (defun ioccur-restart ()
@@ -517,26 +528,24 @@ Move point to first occurence of `ioccur-search-pattern'."
                       nil))))
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
 
-
 (defun ioccur-update-buffer (regexp buffer-name)
   "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
         (progn (erase-buffer) (insert (concat title "\n\n")))
         (erase-buffer)
-        (ioccur-print-buffer regexp :lline ioccur-length-line)
+        (ioccur-print-buffer regexp)
         (goto-char (point-min))
-        (insert (concat title "\n\n"
-                        (propertize (format "Found %s occurences of "
-                                            ioccur-count-occurences)
-                                    'face 'underline)
-                        (propertize regexp 'face 'ioccur-regexp-face)
-                        (propertize
-                         (format " in %s" buffer-name)
-                         'face 'underline) "\n\n"))
+        (insert title "\n\n"
+                (propertize (format "Found %s occurences of "
+                                    ioccur-count-occurences)
+                            'face 'underline)
+                (propertize regexp 'face 'ioccur-regexp-face)
+                (propertize
+                 (format " in %s" buffer-name)
+                 'face 'underline) "\n\n")
         (ioccur-color-current-line))))
 
-
 (defun ioccur-start-timer ()
   "Start ioccur incremental timer."
   (setq ioccur-search-timer

commit 0443e54d6ea5518e5ded4e90a36041f3df4eb04f
Author: Thierry Volpiatto <address@hidden>
Date:   Sun May 9 23:52:11 2010 +0200

    (ioccur-read-lines) Use vconcat loop

diff --git a/ioccur.el b/ioccur.el
index 5187c48..60c74ab 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -217,9 +217,9 @@ Special commands:
        for count from 0
        for line = (buffer-substring (point-at-bol) (point-at-eol))
        when (string-match regexp line)
-       collect (list count line) into lis
+       vconcat (list (list count line)) into vec
        do (forward-line 1)
-       finally return (vconcat lis))))
+       finally return vec)))
 
 (defsubst* ioccur-print-buffer (regex &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."

commit 2155b23c958ce10f8ade325add2d9372b99a7c8d
Author: Thierry Volpiatto <address@hidden>
Date:   Sat May 8 11:57:16 2010 +0200

    (ioccur-print-buffer) Use defsubst*

diff --git a/ioccur.el b/ioccur.el
index 313082e..5187c48 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -221,7 +221,7 @@ Special commands:
        do (forward-line 1)
        finally return (vconcat lis))))
 
-(defun* ioccur-print-buffer (regex &key (lline ioccur-length-line))
+(defsubst* ioccur-print-buffer (regex &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines regex)))

commit 4fc251c60082315ceaa048c1a830affc9f86c050
Author: Thierry Volpiatto <address@hidden>
Date:   Sat May 8 11:38:14 2010 +0200

    Fix yank stuff at point with new `ioccur-find-readlines' that push point to 
point-max.

diff --git a/ioccur.el b/ioccur.el
index 203a0f7..313082e 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -428,8 +428,7 @@ Move point to first occurence of `ioccur-search-pattern'."
            (insert-initial-input ()
              (unless (string= initial-input "")
                (loop for char across initial-input
-                  do (push char tmp-list)))
-             (setq ioccur-search-pattern initial-input))
+                  do (push char tmp-list))))
            ;; Maybe start timer.
            ;;
            (start-timer ()
@@ -491,11 +490,16 @@ Move point to first occurence of `ioccur-search-pattern'."
                  (?\C-w                         ; Yank stuff at point.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
-                    (unless old-yank-point (setq old-yank-point (point)))
-                    (setq yank-point (point)) (forward-word 1)
+                    ;; Start to initial point if C-w have never been hit.
+                    (unless yank-point (setq yank-point old-yank-point))
+                    ;; After a search `ioccur-find-readlines' have put point
+                    ;; to point-max, so reset position.
+                    (when yank-point (goto-char yank-point))
+                    (forward-word 1)
                     (setq initial-input (buffer-substring-no-properties
                                          yank-point (point)))
-                  (insert-initial-input) t))
+                    (setq yank-point (point))   ; End of last forward-word
+                    (insert-initial-input) t))
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))

commit 992e464be8f5968548dd7ffeed383938c306e48a
Author: Thierry Volpiatto <address@hidden>
Date:   Sat May 8 10:01:00 2010 +0200

    Use now a vector to store results.
    (ioccur-find-readlines) return a vector
    (ioccur-print-buffer) use loop to parse vector returned by *-readlines, 
doesn't use buffer arg.
    (ioccur) Send message when fontifying.

diff --git a/ioccur.el b/ioccur.el
index 549d952..203a0f7 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -219,25 +219,27 @@ Special commands:
        when (string-match regexp line)
        collect (list count line) into lis
        do (forward-line 1)
-       finally return lis)))
+       finally return (vconcat lis))))
 
-(defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))
+(defun* ioccur-print-buffer (regex &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines regex)))
     (when matched-lines
-      (dolist (i matched-lines) ; Each element is of the form '(key value)
-        (let* ((line           (second i))
-               (replace-reg   (if (string-match "^\t" line)
-                                  "\\(^\t*\\)" "\\(^ *\\)"))
-               (lineno        (int-to-string (1+ (first i))))
-               (ltp (replace-regexp-in-string replace-reg "" line))
-               (trunc-line    (if (> (length ltp) lline)
-                                  (substring ltp 0 lline) ltp)))
-          (incf ioccur-count-occurences)
-          (insert (concat " " (propertize lineno 'face 'ioccur-num-line-face
-                                          'help-echo ltp)
-                          ":" trunc-line "\n")))))))
+      (loop for i across matched-lines
+         for line        = (second i)
+         for bol-reg     = (if (string-match "^\t" line)
+                               "\\(^\t*\\)" "\\(^ *\\)")
+         for lineno      = (int-to-string (1+ (first i)))
+         for ltp         = (replace-regexp-in-string bol-reg "" line)
+         for trunc-line  = (if (> (length ltp) lline)
+                               (substring ltp 0 lline) ltp)
+         do
+           (progn
+             (incf ioccur-count-occurences)
+             (insert (concat " " (propertize lineno 'face 'ioccur-num-line-face
+                                             'help-echo ltp)
+                             ":" trunc-line "\n")))))))
 
 ;;;###autoload
 (defun ioccur-restart ()
@@ -491,8 +493,9 @@ Move point to first occurence of `ioccur-search-pattern'."
                   (with-current-buffer ioccur-current-buffer
                     (unless old-yank-point (setq old-yank-point (point)))
                     (setq yank-point (point)) (forward-word 1)
-                    (setq initial-input (buffer-substring yank-point (point))))
-                  (insert-initial-input) t)
+                    (setq initial-input (buffer-substring-no-properties
+                                         yank-point (point)))
+                  (insert-initial-input) t))
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))
@@ -517,7 +520,7 @@ Move point to first occurence of `ioccur-search-pattern'."
     (if (string= regexp "")
         (progn (erase-buffer) (insert (concat title "\n\n")))
         (erase-buffer)
-        (ioccur-print-buffer regexp buffer-name :lline ioccur-length-line)
+        (ioccur-print-buffer regexp :lline ioccur-length-line)
         (goto-char (point-min))
         (insert (concat title "\n\n"
                         (propertize (format "Found %s occurences of "
@@ -580,11 +583,15 @@ for commands provided in the `ioccur-buffer'."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
-  (jit-lock-fontify-now)
+  (message "Fontifying buffer...Please wait it could be long.")
+  (jit-lock-fontify-now) (message nil)
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
   (if (and (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
+      ;; An hidden `ioccur-buffer' exists jump to it.
       (pop-to-buffer ioccur-buffer t)
+      ;; `ioccur-buffer' doesn't exists or is not visible
+      ;; Start incremental search.
       (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
              (len      (length init-str))
              (curpos   (point))

commit 8c055a4f0ff8659d4433aafce0ff478a78aa3b39
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 7 22:37:35 2010 +0200

    fix error in ioccur-print-buffer, simplify jit-font.. in ioccur.

diff --git a/ioccur.el b/ioccur.el
index ad3f259..549d952 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -224,7 +224,7 @@ Special commands:
 (defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
-  (let ((matched-lines (ioccur-find-readlines buffer regex)))
+  (let ((matched-lines (ioccur-find-readlines regex)))
     (when matched-lines
       (dolist (i matched-lines) ; Each element is of the form '(key value)
         (let* ((line           (second i))
@@ -580,11 +580,11 @@ for commands provided in the `ioccur-buffer'."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
+  (jit-lock-fontify-now)
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
   (if (and (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
       (pop-to-buffer ioccur-buffer t)
-      (with-current-buffer ioccur-current-buffer (jit-lock-fontify-now))
       (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
              (len      (length init-str))
              (curpos   (point))

commit c9e7b404deb20aed5ec004b2253e6415915b4b93
Author: Thierry Volpiatto <address@hidden>
Date:   Fri May 7 22:09:01 2010 +0200

    align map, make ioccur-find-readlines a little faster, clean 
ioccur-print-buffer.

diff --git a/ioccur.el b/ioccur.el
index 61ea66f..ad3f259 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -39,21 +39,21 @@
 
 (defvar ioccur-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "q") 'ioccur-quit)
-    (define-key map (kbd "RET") 'ioccur-jump-and-quit)
-    (define-key map (kbd "<left>") 'ioccur-jump-and-quit)
-    (define-key map (kbd "<right>") 'ioccur-jump-without-quit)
-    (define-key map (kbd "C-z") 'ioccur-jump-without-quit)
+    (define-key map (kbd "q")        'ioccur-quit)
+    (define-key map (kbd "RET")      'ioccur-jump-and-quit)
+    (define-key map (kbd "<left>")   'ioccur-jump-and-quit)
+    (define-key map (kbd "<right>")  'ioccur-jump-without-quit)
+    (define-key map (kbd "C-z")      'ioccur-jump-without-quit)
     (define-key map (kbd "<C-down>") 'ioccur-scroll-down)
-    (define-key map (kbd "<C-up>") 'ioccur-scroll-up)
-    (define-key map (kbd "C-v") 'ioccur-scroll-other-window-up)
-    (define-key map (kbd "M-v") 'ioccur-scroll-other-window-down)
-    (define-key map (kbd "<down>") 'ioccur-next-line)
-    (define-key map (kbd "<up>") 'ioccur-precedent-line)
-    (define-key map (kbd "C-n") 'ioccur-next-line)
-    (define-key map (kbd "C-p") 'ioccur-precedent-line)
-    (define-key map (kbd "R") 'ioccur-restart)
-    (define-key map (kbd "C-|") 'ioccur-split-window)
+    (define-key map (kbd "<C-up>")   'ioccur-scroll-up)
+    (define-key map (kbd "C-v")      'ioccur-scroll-other-window-up)
+    (define-key map (kbd "M-v")      'ioccur-scroll-other-window-down)
+    (define-key map (kbd "<down>")   'ioccur-next-line)
+    (define-key map (kbd "<up>")     'ioccur-precedent-line)
+    (define-key map (kbd "C-n")      'ioccur-next-line)
+    (define-key map (kbd "C-p")      'ioccur-precedent-line)
+    (define-key map (kbd "R")        'ioccur-restart)
+    (define-key map (kbd "C-|")      'ioccur-split-window)
     map)
   "Keymap used for ioccur commands.")
 
@@ -78,8 +78,10 @@
   (if (window-system)
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
 C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
+
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
 C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank 
tap")
+
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
@@ -206,19 +208,18 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'buffer))
-  "Return an alist of all the (numline line)  matching REGEXP."
-  (let ((fn (case insert-fn
-              ('file 'insert-file-contents)
-              ('buffer 'insert-buffer-substring))))
-    (with-temp-buffer
-      (funcall fn bfile) ; call insert function
-      (goto-char (point-min))
-      (loop
-         with lines-list = (split-string (buffer-string) "\n")
-         for i in lines-list for count from 0 when (string-match regexp i)
-         collect (list count i) into lis
-         finally return lis))))
+(defsubst ioccur-find-readlines (regexp)
+  "Return an alist of all the (numline line) matching REGEXP."
+  (with-current-buffer ioccur-current-buffer
+    (goto-char (point-min))
+    (loop
+       while (not (eobp))
+       for count from 0
+       for line = (buffer-substring (point-at-bol) (point-at-eol))
+       when (string-match regexp line)
+       collect (list count line) into lis
+       do (forward-line 1)
+       finally return lis)))
 
 (defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."
@@ -226,21 +227,17 @@ Special commands:
   (let ((matched-lines (ioccur-find-readlines buffer regex)))
     (when matched-lines
       (dolist (i matched-lines) ; Each element is of the form '(key value)
-        (let* ((ltp           (second i))
-               (replace-reg   (if (string-match "^\t" ltp)
+        (let* ((line           (second i))
+               (replace-reg   (if (string-match "^\t" line)
                                   "\\(^\t*\\)" "\\(^ *\\)"))
-               (new-ltp       (replace-regexp-in-string replace-reg "" ltp))
-               (line-to-print new-ltp))
+               (lineno        (int-to-string (1+ (first i))))
+               (ltp (replace-regexp-in-string replace-reg "" line))
+               (trunc-line    (if (> (length ltp) lline)
+                                  (substring ltp 0 lline) ltp)))
           (incf ioccur-count-occurences)
-          (insert (concat " " (propertize (int-to-string (+ (first i) 1))
-                                          'face 'ioccur-num-line-face
-                                          'help-echo line-to-print)
-                          ":"
-                          (if (> (length line-to-print) lline)
-                              (substring line-to-print 0 lline)
-                              line-to-print)
-                          "\n")))))))
-
+          (insert (concat " " (propertize lineno 'face 'ioccur-num-line-face
+                                          'help-echo ltp)
+                          ":" trunc-line "\n")))))))
 
 ;;;###autoload
 (defun ioccur-restart ()
@@ -587,8 +584,7 @@ for commands provided in the `ioccur-buffer'."
   (if (and (get-buffer ioccur-buffer)
            (not (get-buffer-window ioccur-buffer)))
       (pop-to-buffer ioccur-buffer t)
-      (with-current-buffer ioccur-current-buffer
-        (jit-lock-fontify-now))
+      (with-current-buffer ioccur-current-buffer (jit-lock-fontify-now))
       (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
              (len      (length init-str))
              (curpos   (point))
@@ -608,7 +604,7 @@ for commands provided in the `ioccur-buffer'."
             (kill-local-variable 'mode-line-format)
             (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
               (setq ioccur-quit-flag t))
-            (cond (ioccur-quit-flag       ; C-g hit.
+            (cond (ioccur-quit-flag       ; C-g hit or empty `ioccur-buffer'.
                    (kill-buffer ioccur-buffer)
                    (switch-to-buffer ioccur-current-buffer)
                    (when ioccur-match-overlay

commit c04b86940c4a3ec9bfb0e673bdebef519e33bec9
Merge: a9bd319 e3b4267
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 5 10:07:37 2010 +0200

    Merge tags in development.


commit a9bd3195f738c0df97e4fe90a5609ba4d170f730
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 5 10:05:40 2010 +0200

    Added tag V-1.3 for changeset 14ecc98f90a1

commit 6aa49cb32493047d161016f05aa434a8ef8fc94c
Merge: e3b4267 f745b1b
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 5 10:04:43 2010 +0200

    Merge with development branch.


commit e3b426723e137d512f5ad33fda47f079d1e04959
Author: Thierry Volpiatto <address@hidden>
Date:   Wed May 5 08:57:34 2010 +0200

    (ioccur-jump-without-quit) Do nothing when no candidates.

diff --git a/ioccur.el b/ioccur.el
index 694bbaf..61ea66f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -316,7 +316,7 @@ Move point to first occurence of `ioccur-search-pattern'."
 (defun ioccur-jump-without-quit ()
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
-  (ioccur-jump) (other-window 1))
+  (when (ioccur-jump) (other-window 1)))
 
 ;;;###autoload
 (defun ioccur-scroll-other-window-down ()

commit 407e945f53b5623e5ed01deb473b23762979a720
Author: Thierry Volpiatto <address@hidden>
Date:   Sun May 2 14:37:21 2010 +0200

    (ioccur-read-search-input) Bugfix:let bind inhibit-quit on windows-nt.

diff --git a/ioccur.el b/ioccur.el
index 6dd335f..694bbaf 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -374,7 +374,8 @@ Move point to first occurence of `ioccur-search-pattern'."
   "Read each keyboard input and add it to `ioccur-search-pattern'."
   (let* ((prompt         (propertize ioccur-search-prompt
                                      'face 'minibuffer-prompt))
-         (inhibit-quit   (not (fboundp 'read-key)))
+         (inhibit-quit   (or (eq system-type 'windows-nt)
+                             (not (fboundp 'read-key))))
          (tmp-list       ())
          (it-prec        nil)
          (it-next        nil)

commit b3a37055c65399dffcd3def69d26c9c43418acf0
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 21 20:42:04 2010 +0200

    Get rid of ioccur-visible-window-p by using get-buffer-window (Thank you 
Stefan ;-)).

diff --git a/ioccur.el b/ioccur.el
index 0666b38..6dd335f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -241,20 +241,6 @@ Special commands:
                               line-to-print)
                           "\n")))))))
 
-;; FIXME: Don't work correctly with one buffer splitted in two
-;; and an other buffer.
-(defun ioccur-visible-buffer-p (buffer)
-  "Can i see this buffer in this window."
-  (let ((buf        (current-buffer))
-        (cur-w-conf (current-window-configuration)))
-    (or (eq buf (get-buffer buffer))
-        (save-window-excursion
-          (pop-to-buffer buffer)
-          (pop-to-buffer buf)
-          ;; If BUFFER is NOT in same window than BUF
-          ;; We should have now another window configuration.
-          (compare-window-configurations
-           cur-w-conf (current-window-configuration))))))
 
 ;;;###autoload
 (defun ioccur-restart ()
@@ -598,7 +584,7 @@ for commands provided in the `ioccur-buffer'."
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
   (if (and (get-buffer ioccur-buffer)
-           (not (ioccur-visible-buffer-p ioccur-buffer)))
+           (not (get-buffer-window ioccur-buffer)))
       (pop-to-buffer ioccur-buffer t)
       (with-current-buffer ioccur-current-buffer
         (jit-lock-fontify-now))

commit 894b232671f1adeb4acdc7a5dd135087b3cbc224
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 21 10:11:58 2010 +0200

    (ioccur-visible-buffer-p) Dont compare window-configuration when 
current-buffer is the one we search.

diff --git a/ioccur.el b/ioccur.el
index 7aa0b9b..0666b38 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -247,13 +247,14 @@ Special commands:
   "Can i see this buffer in this window."
   (let ((buf        (current-buffer))
         (cur-w-conf (current-window-configuration)))
-    (save-window-excursion
-      (pop-to-buffer buffer)
-      (pop-to-buffer buf)
-      ;; If BUFFER is NOT in same window than BUF
-      ;; We should have now another window configuration.
-      (compare-window-configurations
-       cur-w-conf (current-window-configuration)))))
+    (or (eq buf (get-buffer buffer))
+        (save-window-excursion
+          (pop-to-buffer buffer)
+          (pop-to-buffer buf)
+          ;; If BUFFER is NOT in same window than BUF
+          ;; We should have now another window configuration.
+          (compare-window-configurations
+           cur-w-conf (current-window-configuration))))))
 
 ;;;###autoload
 (defun ioccur-restart ()

commit db3934140540fe059bac10b898f191e41fa40ef9
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 21 09:52:00 2010 +0200

    Fix splitting windows in info buffers.(use 'other-window arg of 
pop-to-buffer)

diff --git a/ioccur.el b/ioccur.el
index 20fcf71..7aa0b9b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -241,11 +241,13 @@ Special commands:
                               line-to-print)
                           "\n")))))))
 
+;; FIXME: Don't work correctly with one buffer splitted in two
+;; and an other buffer.
 (defun ioccur-visible-buffer-p (buffer)
   "Can i see this buffer in this window."
-  (save-window-excursion
-    (let ((buf        (current-buffer))
-          (cur-w-conf (current-window-configuration)))
+  (let ((buf        (current-buffer))
+        (cur-w-conf (current-window-configuration)))
+    (save-window-excursion
       (pop-to-buffer buffer)
       (pop-to-buffer buf)
       ;; If BUFFER is NOT in same window than BUF
@@ -305,7 +307,7 @@ Move point to first occurence of `ioccur-search-pattern'."
          (pos  (string-to-number line)))
     (unless (or (string= line "")
                 (string= line "Ioccur"))
-      (pop-to-buffer ioccur-current-buffer)
+      (pop-to-buffer ioccur-current-buffer t)
       (ioccur-goto-line pos)
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-search-pattern'.
@@ -596,7 +598,7 @@ for commands provided in the `ioccur-buffer'."
   (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
   (if (and (get-buffer ioccur-buffer)
            (not (ioccur-visible-buffer-p ioccur-buffer)))
-      (pop-to-buffer ioccur-buffer)
+      (pop-to-buffer ioccur-buffer t)
       (with-current-buffer ioccur-current-buffer
         (jit-lock-fontify-now))
       (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
@@ -605,7 +607,7 @@ for commands provided in the `ioccur-buffer'."
              str-no-prop)
         (set-text-properties 0 len nil init-str)
         (setq str-no-prop init-str)
-        (pop-to-buffer (get-buffer-create ioccur-buffer))
+        (pop-to-buffer (get-buffer-create ioccur-buffer) t)
         (ioccur-mode)
         (unwind-protect
              ;; Start incremental search.

commit dcbd38ad7fd6143c768225a207ba73e65b244909
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Apr 18 15:40:28 2010 +0200

    (ioocur-find-readlines) Better counter, Removing newline seem unuseful 
here.(replace-regexp-in-string..).

diff --git a/ioccur.el b/ioccur.el
index baaf2aa..20fcf71 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -208,18 +208,16 @@ Special commands:
 
 (defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'buffer))
   "Return an alist of all the (numline line)  matching REGEXP."
-  (let ((count 0)
-        (fn    (case insert-fn
-                 ('file 'insert-file-contents)
-                 ('buffer 'insert-buffer-substring))))
+  (let ((fn (case insert-fn
+              ('file 'insert-file-contents)
+              ('buffer 'insert-buffer-substring))))
     (with-temp-buffer
       (funcall fn bfile) ; call insert function
       (goto-char (point-min))
       (loop
          with lines-list = (split-string (buffer-string) "\n")
-         for i in lines-list when (string-match regexp i)
-         collect (list count (replace-regexp-in-string "\n" "" i)) into lis
-         do (incf count)
+         for i in lines-list for count from 0 when (string-match regexp i)
+         collect (list count i) into lis
          finally return lis))))
 
 (defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))

commit 629f048d1eb108b5072e255694bd730f8162ea6b
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Apr 15 12:46:40 2010 +0200

    Add a nil message after reading key.

diff --git a/ioccur.el b/ioccur.el
index e18efb0..baaf2aa 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -456,6 +456,7 @@ Move point to first occurence of `ioccur-search-pattern'."
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-search-pattern))))
+               (message nil)
                (case char
                  ((not (?\M-p ?\M-n ?\t C-tab)) ; Reset history
                   (setq start-hist nil)
@@ -472,7 +473,7 @@ Move point to first occurence of `ioccur-search-pattern'."
                  ((?\C-u C-up)                  ; Scroll both windows up.
                   (stop-timer) (ioccur-scroll-up) t)
                  (?\r                           ; RET break and exit code.
-                  (message nil) nil)
+                  nil)
                  (?\d                           ; Delete backward with DEL.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer

commit 785f2b3311c297b7ccab05e491a86ddfaf3e7f00
Merge: 2fc5241 f745b1b
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 14 13:36:19 2010 +0200

    Merge tags


commit f745b1b462f58e0b441228ef3112bdd9e0427789
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 14 13:33:56 2010 +0200

    Added tag V-1.2 for changeset 65b107b2c7f2

commit ca946771586ed82ebcd45b71b294e765d49aeca2
Merge: 2fc5241 655415c
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 14 13:32:53 2010 +0200

    Merge branchs.


commit 3361618a19d4bf4ee835c183a98d439b4c861f3b
Author: mooz <address@hidden>
Date:   Tue Apr 13 10:51:10 2010 +0900

    Fixed the indentation for braceless 'for each'.

diff --git a/js2-mode.el b/js2-mode.el
index 292987e..03aee99 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9597,11 +9597,16 @@ not `js2-NAME', then we use the token info saved in 
instance vars."
 
 (defconst js-possibly-braceless-keyword-re
   (regexp-opt
-   '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let")
+   '("catch" "do" "else" "finally" "for" "if" "each" "try" "while" "with" 
"let")
    'words)
   "Regular expression matching keywords that are optionally
 followed by an opening brace.")
 
+(defconst js-possibly-braceless-keywords-re
+  "\\([ \t}]*else[ \t]+if\\|[ \t}]*for[ \t]+each\\)"
+  "Regular expression which matches the keywords which are consist of more 
than 2 words
+like 'if else' and 'for each', and optionally followed by an opening brace.")
+
 (defconst js-indent-operator-re
   (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
           (regexp-opt '("in" "instanceof") 'words))
@@ -9779,7 +9784,7 @@ returns nil."
                                 (and (backward-word 1)
                                      (skip-chars-backward " \t}" 
(point-at-bol))
                                      (bolp)
-                                     (looking-at "[ \t}]*else[ \t]+if"))))
+                                     (looking-at 
js-possibly-braceless-keywords-re))))
                           (looking-at js-possibly-braceless-keyword-re)
                           (not (js-end-of-do-while-loop-p))))))
         (save-excursion

commit 27519a39b79cc2dc7e3ab0f6a276b3aaec1156cc
Author: mooz <address@hidden>
Date:   Tue Apr 13 10:50:52 2010 +0900

    :)

diff --git a/js2-mode.el b/js2-mode.el
index 09d8f5e..292987e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009  Free Software Foundation, Inc.
 
 ;; Author:  Steve Yegge <address@hidden>
+;;          mooz        <address@hidden>
 ;; Version:  See `js2-mode-version'
 ;; Keywords:  languages, javascript
 

commit 2fc5241ff263ac939d53169cb7eef67282546886
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Apr 7 11:26:31 2010 +0200

    (ioccur-read-search-input) Add insert-initial-input in flet.

diff --git a/ioccur.el b/ioccur.el
index 2c32eb7..e18efb0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -436,6 +436,13 @@ Move point to first occurence of `ioccur-search-pattern'."
                        (setq ioccur-search-pattern cur-hist-elm)
                        (setq start-hist t)))
                  (message "No history available.") (sit-for 2) t))
+           ;; Insert INITIAL-INPUT.
+           ;;
+           (insert-initial-input ()
+             (unless (string= initial-input "")
+               (loop for char across initial-input
+                  do (push char tmp-list)))
+             (setq ioccur-search-pattern initial-input))
            ;; Maybe start timer.
            ;;
            (start-timer ()
@@ -492,20 +499,14 @@ Move point to first occurence of `ioccur-search-pattern'."
                   (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
                  (?\C-y                         ; Yank from `kill-ring'.
                   (setq initial-input (car kill-ring))
-                  (unless (string= initial-input "")
-                    (loop for char across initial-input
-                       do (push char tmp-list)))
-                  (setq ioccur-search-pattern initial-input) t)
+                  (insert-initial-input) t)
                  (?\C-w                         ; Yank stuff at point.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (unless old-yank-point (setq old-yank-point (point)))
                     (setq yank-point (point)) (forward-word 1)
                     (setq initial-input (buffer-substring yank-point (point))))
-                  (unless (string= initial-input "")
-                    (loop for char across initial-input
-                       do (push char tmp-list)))
-                  (setq ioccur-search-pattern initial-input) t)
+                  (insert-initial-input) t)
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))

commit 5d5c434ee01195071e176bb3821743cd5df01ed8
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Apr 6 12:15:28 2010 +0200

    (ioccur): Make code more readable with cond and new func 
`ioccur-save-history'.

diff --git a/ioccur.el b/ioccur.el
index bbf1aa1..2c32eb7 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -618,37 +618,38 @@ for commands provided in the `ioccur-buffer'."
             (kill-local-variable 'mode-line-format)
             (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
               (setq ioccur-quit-flag t))
-            (if ioccur-quit-flag        ; C-g
-                (progn
-                  (kill-buffer ioccur-buffer)
-                  (switch-to-buffer ioccur-current-buffer)
-                  (when ioccur-match-overlay
-                    (delete-overlay ioccur-match-overlay))
-                  (delete-other-windows) (goto-char curpos) (message nil))
-
-                (if ioccur-exit-and-quit-p
-                    (progn (ioccur-jump-and-quit)
-                           (kill-buffer ioccur-buffer) (message nil))
-                    (ioccur-jump) (other-window 1))
-                ;; Push elm in history if not already there or empty.
-                (unless (or (member ioccur-search-pattern ioccur-history)
-                            (string= ioccur-search-pattern ""))
-                  (push ioccur-search-pattern ioccur-history))
-                ;; If elm already exists in history ring
-                ;; push it on top of stack.
-                (let ((pos-hist-elm (ioccur-position
-                                     ioccur-search-pattern
-                                     ioccur-history :test 'equal)))
-                  (unless (string= (car ioccur-history)
-                                   ioccur-search-pattern)
-                    (push (pop (nthcdr pos-hist-elm ioccur-history))
-                          ioccur-history)))
-                (when (> (length ioccur-history) ioccur-max-length-history)
-                  (setq ioccur-history (delete (car (last ioccur-history))
-                                               ioccur-history))))
+            (cond (ioccur-quit-flag       ; C-g hit.
+                   (kill-buffer ioccur-buffer)
+                   (switch-to-buffer ioccur-current-buffer)
+                   (when ioccur-match-overlay
+                     (delete-overlay ioccur-match-overlay))
+                   (delete-other-windows) (goto-char curpos) (message nil))
+                  (ioccur-exit-and-quit-p ; Jump and kill `ioccur-buffer'.
+                   (ioccur-jump-and-quit) (kill-buffer ioccur-buffer)
+                   (message nil) (ioccur-save-history))
+                  (t                      ; Jump keeping `ioccur-buffer'.
+                   (ioccur-jump) (other-window 1) (ioccur-save-history)))
             (setq ioccur-count-occurences 0)
             (setq ioccur-quit-flag nil))))))
 
+(defun ioccur-save-history ()
+  "Save last ioccur element found in `ioccur-history'."
+  ;; Push elm in history if not already there or empty.
+  (unless (or (member ioccur-search-pattern ioccur-history)
+              (string= ioccur-search-pattern ""))
+    (push ioccur-search-pattern ioccur-history))
+  ;; If elm already exists in history ring
+  ;; push it on top of stack.
+  (let ((pos-hist-elm (ioccur-position
+                       ioccur-search-pattern
+                       ioccur-history :test 'equal)))
+    (unless (string= (car ioccur-history)
+                     ioccur-search-pattern)
+      (push (pop (nthcdr pos-hist-elm ioccur-history))
+            ioccur-history)))
+  (when (> (length ioccur-history) ioccur-max-length-history)
+    (setq ioccur-history (delete (car (last ioccur-history))
+                                 ioccur-history))))
 
 (defun ioccur-cancel-search ()
   "Cancel timer used for ioccur searching."

commit 8f272d9b68214b42b98aee869306a1c635035be1
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Apr 6 11:36:42 2010 +0200

    (ioccur) Fix docstring.

diff --git a/ioccur.el b/ioccur.el
index 64f0ee4..bbf1aa1 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -564,8 +564,8 @@ C-n or <down>  next line.
 C-p or <up>    precedent line.
 C-v and M-v    scroll up and down.
 C-z or <right> jump without quitting loop.
-C-j or <left>  jump and exit search buffer.
-RET            exit but don't quit search buffer.
+C-j or <left>  jump and kill `ioccur-buffer'.
+RET            exit keeping `ioccur-buffer'.
 DEL            remove last character entered.
 C-k            Kill current input.
 C-w            Yank stuff at point.
@@ -589,7 +589,7 @@ Special NOTE for terms:
   Use C-t to Scroll up.
  
 When you quit incremental search with RET, see `ioccur-mode'
-for commands provided in the search buffer."
+for commands provided in the `ioccur-buffer'."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))

commit 24ae0ad14fa1492633e1ab513cd3e265c9ad0e57
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Apr 5 21:30:03 2010 +0200

    (ioccur-jump) Fix: Don't forward-char before back searching.

diff --git a/ioccur.el b/ioccur.el
index 272aaf6..64f0ee4 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -312,7 +312,6 @@ Move point to first occurence of `ioccur-search-pattern'."
       ;; Go to beginning of first occurence in this line
       ;; of what match `ioccur-search-pattern'.
       (when (re-search-forward ioccur-search-pattern (point-at-eol) t)
-        (forward-char 1)
         (re-search-backward ioccur-search-pattern (point-at-bol) t))
       (ioccur-color-matched-line))))
 

commit 6af9e057038af834525962ad885e26b52e927f0a
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Apr 5 12:07:33 2010 +0200

    Fix all lines with +80 columns.

diff --git a/ioccur.el b/ioccur.el
index 38809e0..272aaf6 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -76,8 +76,10 @@
 
 (defcustom ioccur-mode-line-string
   (if (window-system)
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
+C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, \
+C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank 
tap")
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
@@ -94,23 +96,28 @@ Set it to nil to remove doc in mode-line."
   :type 'integer)
 
 ;;; Faces.
-(defface ioccur-overlay-face '((t (:background "Green4" :underline t)))
+(defface ioccur-overlay-face
+    '((t (:background "Green4" :underline t)))
   "Face for highlight line in ioccur buffer."
   :group 'ioccur-faces)
 
-(defface ioccur-match-overlay-face '((t (:background "Indianred4" :underline 
t)))
+(defface ioccur-match-overlay-face
+    '((t (:background "Indianred4" :underline t)))
   "Face for highlight line in matched buffer."
   :group 'ioccur-faces)
 
-(defface ioccur-title-face '((t (:background "Dodgerblue4")))
+(defface ioccur-title-face
+    '((t (:background "Dodgerblue4")))
   "Face for highlight incremental buffer title."
   :group 'ioccur-faces)
 
-(defface ioccur-regexp-face '((t (:background "DeepSkyBlue" :underline t)))
+(defface ioccur-regexp-face
+    '((t (:background "DeepSkyBlue" :underline t)))
   "Face for highlight found regexp in incremental buffer."
   :group 'ioccur-faces)
 
-(defface ioccur-num-line-face '((t (:foreground "OrangeRed")))
+(defface ioccur-num-line-face
+    '((t (:foreground "OrangeRed")))
   "Face for highlight number line in ioccur buffer."
   :group 'ioccur-faces)
 
@@ -470,7 +477,7 @@ Move point to first occurence of `ioccur-search-pattern'."
                   (setq ioccur-quit-flag t) nil)
                  ((right ?\C-z)                 ; Persistent action.
                   (ioccur-jump-without-quit) t)
-                 ((left ?\C-j)                  ; Jump to candidate and kill 
search buffer.
+                 ((left ?\C-j)                  ; Jump and kill search buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
                  ((next ?\C-v)                  ; Scroll down.
                   (ioccur-scroll-other-window-down) t)
@@ -628,9 +635,11 @@ for commands provided in the search buffer."
                 (unless (or (member ioccur-search-pattern ioccur-history)
                             (string= ioccur-search-pattern ""))
                   (push ioccur-search-pattern ioccur-history))
-                ;; If elm already exists in history ring push it on top of 
stack.
-                (let ((pos-hist-elm (ioccur-position ioccur-search-pattern
-                                                     ioccur-history :test 
'equal)))
+                ;; If elm already exists in history ring
+                ;; push it on top of stack.
+                (let ((pos-hist-elm (ioccur-position
+                                     ioccur-search-pattern
+                                     ioccur-history :test 'equal)))
                   (unless (string= (car ioccur-history)
                                    ioccur-search-pattern)
                     (push (pop (nthcdr pos-hist-elm ioccur-history))

commit 1b02a8026f17c9246f4ce667dcf5388c53cb3f65
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Apr 5 11:16:43 2010 +0200

    (ioccur-jump): Move point to first occurence of `ioccur-search-pattern' 
when jumping.

diff --git a/ioccur.el b/ioccur.el
index 7c238f3..38809e0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -294,13 +294,20 @@ Special commands:
   (ioccur-forward-line -1))
 
 (defun ioccur-jump ()
-  "Jump to line in other buffer and put an overlay on it."
+  "Jump to line in other buffer and put an overlay on it.
+Move point to first occurence of `ioccur-search-pattern'."
   (let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
          (pos  (string-to-number line)))
     (unless (or (string= line "")
                 (string= line "Ioccur"))
       (pop-to-buffer ioccur-current-buffer)
-      (ioccur-goto-line pos) (ioccur-color-matched-line))))
+      (ioccur-goto-line pos)
+      ;; Go to beginning of first occurence in this line
+      ;; of what match `ioccur-search-pattern'.
+      (when (re-search-forward ioccur-search-pattern (point-at-eol) t)
+        (forward-char 1)
+        (re-search-backward ioccur-search-pattern (point-at-bol) t))
+      (ioccur-color-matched-line))))
 
 ;;;###autoload
 (defun ioccur-jump-and-quit ()

commit 9cf094772ca4d906e0cf37854a10d05952d2afaf
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Apr 4 14:48:44 2010 +0200

    (ioccur-jump): Simplify, faster,do not use regexp and match-string.

diff --git a/ioccur.el b/ioccur.el
index 6f2b561..7c238f3 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -295,16 +295,13 @@ Special commands:
 
 (defun ioccur-jump ()
   "Jump to line in other buffer and put an overlay on it."
-  (let ((line (buffer-substring (point-at-bol) (point-at-eol)))
-        pos)
+  (let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
+         (pos  (string-to-number line)))
     (unless (or (string= line "")
                 (string= line "Ioccur"))
-      (when (string-match "[0-9]+" line)
-        (setq pos (string-to-number (match-string 0 line))))
       (pop-to-buffer ioccur-current-buffer)
       (ioccur-goto-line pos) (ioccur-color-matched-line))))
 
-
 ;;;###autoload
 (defun ioccur-jump-and-quit ()
   "Jump to line in other buffer and quit search buffer."

commit 1b224fff44c56b56e954d0dae63289a91d5c270c
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Apr 3 19:53:08 2010 +0200

    Add autoloads cookies.

diff --git a/ioccur.el b/ioccur.el
index 36a74c0..6f2b561 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -315,16 +315,19 @@ Special commands:
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
 
+;;;###autoload
 (defun ioccur-jump-without-quit ()
   "Jump to line in `ioccur-current-buffer' without quiting."
   (interactive)
   (ioccur-jump) (other-window 1))
 
+;;;###autoload
 (defun ioccur-scroll-other-window-down ()
   "Scroll other window down."
   (interactive)
   (scroll-other-window 1))
 
+;;;###autoload
 (defun ioccur-scroll-other-window-up ()
   "Scroll other window up."
   (interactive)

commit b090eee8e12770136771259e764ef1a3323d29b5
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Apr 2 20:27:26 2010 +0200

    Ioccur is now buffer local, each buffer have it's own ioccur-buffer.
    
    (ioccur-buffer): new variable buffer local.
    (ioccur-occur-overlay): now buffer local.
    (ioccur-visible-buffer-p): new check if ioccur-buffer is visible.
    (ioccur-restart): restart incremental search from ioccur-buffer.
    (ioccur-quit): Don't kill buffer.
    (ioccur): If ioccur-buffer exist and is visible start incremental search 
otherwise reuse ioccur-buffer.
    (ioccur-color-current-line): use ioccur-buffer for overlay functions.

diff --git a/ioccur.el b/ioccur.el
index 35ca53a..36a74c0 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -52,6 +52,8 @@
     (define-key map (kbd "<up>") 'ioccur-precedent-line)
     (define-key map (kbd "C-n") 'ioccur-next-line)
     (define-key map (kbd "C-p") 'ioccur-precedent-line)
+    (define-key map (kbd "R") 'ioccur-restart)
+    (define-key map (kbd "C-|") 'ioccur-split-window)
     map)
   "Keymap used for ioccur commands.")
 
@@ -118,10 +120,13 @@ Set it to nil to remove doc in mode-line."
 (defvar ioccur-quit-flag nil)
 (defvar ioccur-current-buffer nil)
 (defvar ioccur-occur-overlay nil)
+(make-variable-buffer-local 'ioccur-occur-overlay)
 (defvar ioccur-exit-and-quit-p nil)
 (defvar ioccur-history nil)
 (defvar ioccur-match-overlay nil)
 (defvar ioccur-count-occurences 0)
+(defvar ioccur-buffer nil)
+(make-variable-buffer-local 'ioccur-buffer)
   
 
 (define-derived-mode ioccur-mode
@@ -231,12 +236,35 @@ Special commands:
                               line-to-print)
                           "\n")))))))
 
+(defun ioccur-visible-buffer-p (buffer)
+  "Can i see this buffer in this window."
+  (save-window-excursion
+    (let ((buf        (current-buffer))
+          (cur-w-conf (current-window-configuration)))
+      (pop-to-buffer buffer)
+      (pop-to-buffer buf)
+      ;; If BUFFER is NOT in same window than BUF
+      ;; We should have now another window configuration.
+      (compare-window-configurations
+       cur-w-conf (current-window-configuration)))))
+
+;;;###autoload
+(defun ioccur-restart ()
+  "Restart `ioccur' from `ioccur-buffer'.
+`ioccur-buffer' is erased and a new search is started."
+  (interactive)
+  (when (and (eq major-mode 'ioccur-mode)
+             (eq (count-windows) 2))
+    (other-window 1)
+    (ioccur)))
+
+;;;###autoload
 (defun ioccur-quit ()
   "Quit and kill ioccur buffer."
   (interactive)
   (when ioccur-match-overlay
     (delete-overlay ioccur-match-overlay))
-  (quit-window t)
+  (quit-window)
   (other-window 1)
   (delete-other-windows))
 
@@ -332,7 +360,7 @@ Special commands:
        (select-window (if (= (window-height) old-size)
                           (split-window-vertically)
                           (split-window-horizontally)))
-       (get-buffer "*ioccur*")))))
+       (get-buffer ioccur-buffer)))))
 
 (defun ioccur-read-char-or-event (prompt)
   "Replace `read-key' when  not available."
@@ -512,7 +540,6 @@ Special commands:
               ioccur-search-pattern
               ioccur-current-buffer)))))
 
-
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.
@@ -553,55 +580,59 @@ for commands provided in the search buffer."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)
   (setq ioccur-current-buffer (buffer-name (current-buffer)))
-  (with-current-buffer ioccur-current-buffer
-    (jit-lock-fontify-now))
-  (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
-         (len      (length init-str))
-         (curpos   (point))
-         str-no-prop)
-    (set-text-properties 0 len nil init-str)
-    (setq str-no-prop init-str)
-    (pop-to-buffer (get-buffer-create "*ioccur*"))
-    (ioccur-mode)
-    (unwind-protect
-         ;; Start incremental search.
-         (progn
-           (ioccur-start-timer)
-           (ioccur-read-search-input str-no-prop curpos))
-      ;; At this point incremental search loop is exited.
-      (progn
-        (ioccur-cancel-search)
-        (kill-local-variable 'mode-line-format)
-        (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
-          (setq ioccur-quit-flag t))
-        (if ioccur-quit-flag ; C-g
-            (progn
-              (kill-buffer "*ioccur*")
-              (switch-to-buffer ioccur-current-buffer)
-              (when ioccur-match-overlay
-                (delete-overlay ioccur-match-overlay))
-              (delete-other-windows) (goto-char curpos) (message nil))
-
-            (if ioccur-exit-and-quit-p
-                (progn (ioccur-jump-and-quit)
-                       (kill-buffer "*ioccur*") (message nil))
-                (ioccur-jump) (other-window 1))
-            ;; Push elm in history if not already there or empty.
-            (unless (or (member ioccur-search-pattern ioccur-history)
-                        (string= ioccur-search-pattern ""))
-              (push ioccur-search-pattern ioccur-history))
-            ;; If elm already exists in history ring push it on top of stack.
-            (let ((pos-hist-elm (ioccur-position ioccur-search-pattern
-                                               ioccur-history :test 'equal)))
-              (unless (string= (car ioccur-history)
-                               ioccur-search-pattern)
-                (push (pop (nthcdr pos-hist-elm ioccur-history))
-                      ioccur-history)))
-            (when (> (length ioccur-history) ioccur-max-length-history)
-              (setq ioccur-history (delete (car (last ioccur-history))
-                                           ioccur-history))))
-        (setq ioccur-count-occurences 0)
-        (setq ioccur-quit-flag nil)))))
+  (setq ioccur-buffer (concat "*ioccur-" ioccur-current-buffer "*"))
+  (if (and (get-buffer ioccur-buffer)
+           (not (ioccur-visible-buffer-p ioccur-buffer)))
+      (pop-to-buffer ioccur-buffer)
+      (with-current-buffer ioccur-current-buffer
+        (jit-lock-fontify-now))
+      (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
+             (len      (length init-str))
+             (curpos   (point))
+             str-no-prop)
+        (set-text-properties 0 len nil init-str)
+        (setq str-no-prop init-str)
+        (pop-to-buffer (get-buffer-create ioccur-buffer))
+        (ioccur-mode)
+        (unwind-protect
+             ;; Start incremental search.
+             (progn
+               (ioccur-start-timer)
+               (ioccur-read-search-input str-no-prop curpos))
+          ;; At this point incremental search loop is exited.
+          (progn
+            (ioccur-cancel-search)
+            (kill-local-variable 'mode-line-format)
+            (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
+              (setq ioccur-quit-flag t))
+            (if ioccur-quit-flag        ; C-g
+                (progn
+                  (kill-buffer ioccur-buffer)
+                  (switch-to-buffer ioccur-current-buffer)
+                  (when ioccur-match-overlay
+                    (delete-overlay ioccur-match-overlay))
+                  (delete-other-windows) (goto-char curpos) (message nil))
+
+                (if ioccur-exit-and-quit-p
+                    (progn (ioccur-jump-and-quit)
+                           (kill-buffer ioccur-buffer) (message nil))
+                    (ioccur-jump) (other-window 1))
+                ;; Push elm in history if not already there or empty.
+                (unless (or (member ioccur-search-pattern ioccur-history)
+                            (string= ioccur-search-pattern ""))
+                  (push ioccur-search-pattern ioccur-history))
+                ;; If elm already exists in history ring push it on top of 
stack.
+                (let ((pos-hist-elm (ioccur-position ioccur-search-pattern
+                                                     ioccur-history :test 
'equal)))
+                  (unless (string= (car ioccur-history)
+                                   ioccur-search-pattern)
+                    (push (pop (nthcdr pos-hist-elm ioccur-history))
+                          ioccur-history)))
+                (when (> (length ioccur-history) ioccur-max-length-history)
+                  (setq ioccur-history (delete (car (last ioccur-history))
+                                               ioccur-history))))
+            (setq ioccur-count-occurences 0)
+            (setq ioccur-quit-flag nil))))))
 
 
 (defun ioccur-cancel-search ()
@@ -610,14 +641,13 @@ for commands provided in the search buffer."
     (cancel-timer ioccur-search-timer)
     (setq ioccur-search-timer nil)))
 
-
 (defun ioccur-color-current-line ()
   "Highlight and underline current line in ioccur buffer."
   (if ioccur-occur-overlay
       (move-overlay ioccur-occur-overlay
-                    (point-at-bol) (1+ (point-at-eol)))
+                    (point-at-bol) (1+ (point-at-eol)) ioccur-buffer)
       (setq ioccur-occur-overlay
-            (make-overlay (point-at-bol) (1+ (point-at-eol)))))
+            (make-overlay (point-at-bol) (1+ (point-at-eol)) ioccur-buffer)))
   (overlay-put ioccur-occur-overlay 'face 'ioccur-overlay-face))
 
 (defun ioccur-color-matched-line ()

commit ab11d1585d32968abe3db2eb2fb094a8303baeba
Author: mooz <address@hidden>
Date:   Fri Apr 2 19:51:53 2010 +0900

    Version 20100402

diff --git a/js2-mode.el b/js2-mode.el
index 4dd8bfb..09d8f5e 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -443,7 +443,7 @@ which doesn't seem particularly useful, but Rhino permits 
it."
   :type 'boolean
   :group 'js2-mode)
 
-(defvar js2-mode-version 20090727
+(defvar js2-mode-version 20100402
   "Release number for `js2-mode'.")
 
 ;; scanner variables

commit 9abd4412c25a5f9e9c1b7717ff9992b848002ea8
Author: mooz <address@hidden>
Date:   Fri Apr 2 19:45:08 2010 +0900

    Fix: when reserved words are used as identifier, js2-mode's parser will 
corrupt.

diff --git a/js2-mode.el b/js2-mode.el
index 52f356f..4dd8bfb 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -5608,7 +5608,7 @@ corresponding number.  Otherwise return -1."
                        (memq result '(js2-LET js2-YIELD)))
                   ;; LET and YIELD are tokens only in 1.7 and later
                   (setq result 'js2-NAME))
-              (if (not (eq result js2-RESERVED))
+              (if (not (eq result 'js2-RESERVED))
                   (throw 'return (js2-token-code result)))
               (js2-report-warning "msg.reserved.keyword" str)))
           ;; If we want to intern these as Rhino does, just use (intern str)

commit 5e2ac1718bfc55bd2724b74a7dd431d9df650fe8
Merge: 655415c 00eb33c
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 30 10:02:52 2010 +0200

    Merge branchs


commit 00eb33c0a1d1f74f2dc3743f4519058cdb34fe3f
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 30 10:00:03 2010 +0200

    (ioccur-read-search-input): Add prior and next for scrolling, remove 
unuseful or.

diff --git a/ioccur.el b/ioccur.el
index 494bc24..35ca53a 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -433,13 +433,13 @@ Special commands:
                   (pop tmp-list) t)
                  (?\C-g                         ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
-                 ((or right ?\C-z)              ; Persistent action.
+                 ((right ?\C-z)                 ; Persistent action.
                   (ioccur-jump-without-quit) t)
                  ((left ?\C-j)                  ; Jump to candidate and kill 
search buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
-                 (?\C-v                         ; Scroll down.
+                 ((next ?\C-v)                  ; Scroll down.
                   (ioccur-scroll-other-window-down) t)
-                 ((?\C-t ?\M-v)                 ; Scroll up.
+                 ((?\C-t ?\M-v prior)           ; Scroll up.
                   (ioccur-scroll-other-window-up) t)
                  (?\C-|                         ; Toggle split window.
                   (ioccur-split-window) t)
@@ -468,7 +468,7 @@ Special commands:
                  ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))
-                 ((backtab ?\M-n)                 ; Next history elm.
+                 ((backtab ?\M-n)               ; Next history elm.
                   (start-timer)
                   (cycle-hist 1))
                  (t                             ; Store character.

commit 655415c67a55e7a3d1799f72dcadd96514500371
Merge: 9ca2813 4430d1e
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 27 19:21:31 2010 +0100

    Version 1.1, merge dev in default branch.


commit 9ca2813851bc5aee4f9c40c173219d594c6ec568
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 27 19:20:02 2010 +0100

    Added tag V-1.1 for changeset 496e9f01d54d

commit 4b1596668958163746c9e8501e6ef937c7e10283
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 27 19:16:40 2010 +0100

    Fix ioccur-mode-line-string.

diff --git a/ioccur.el b/ioccur.el
index 668c272..494bc24 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -74,7 +74,7 @@
 
 (defcustom ioccur-mode-line-string
   (if (window-system)
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Follow, C-w:Yank tap"
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v:Scroll, C-down/up:Follow, C-w:Yank tap"
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."

commit 2c8b96b653857da4edb1d37fc538653e26facdd7
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 27 19:08:01 2010 +0100

    Finally find good commands for history in terms.

diff --git a/ioccur.el b/ioccur.el
index 745a7ed..668c272 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -75,7 +75,7 @@
 (defcustom ioccur-mode-line-string
   (if (window-system)
       " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Follow, C-w:Yank tap"
-      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-d/u:Follow, C-w:Yank tap")
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, Tab/S-tab:Hist, C-v/t:Scroll, C-d/u:Follow, C-w:Yank tap")
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
@@ -408,55 +408,54 @@ Special commands:
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-search-pattern))))
-               (unless (or (equal char ?\M-p) (equal char ?\M-n)
-                           ;; Handle Meta in terms.
-                           (equal char ?\^\[) (equal char ?\^\[))
-                 (setq start-hist nil) (setq cur-hist-elm (car 
ioccur-history)))
                (case char
-                 ((down ?\C-n)       ; Next line.
+                 ((not (?\M-p ?\M-n ?\t C-tab)) ; Reset history
+                  (setq start-hist nil)
+                  (setq cur-hist-elm (car ioccur-history)) t)
+                 ((down ?\C-n)                  ; Next line.
                   (stop-timer) (ioccur-next-line)
                   (ioccur-color-current-line) t)
-                 ((up ?\C-p)         ; Precedent line.
+                 ((up ?\C-p)                    ; Precedent line.
                   (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
-                 ((?\C-d C-down)     ; Scroll both windows down.
+                 ((?\C-d C-down)                ; Scroll both windows down.
                   (stop-timer)
                   (ioccur-scroll-down) t)
-                 ((?\C-u C-up)       ; Scroll both windows up.
+                 ((?\C-u C-up)                  ; Scroll both windows up.
                   (stop-timer) (ioccur-scroll-up) t)
-                 (?\r                ; RET break and exit code.
+                 (?\r                           ; RET break and exit code.
                   (message nil) nil)
-                 (?\d                ; Delete backward with DEL.
+                 (?\d                           ; Delete backward with DEL.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
                   (pop tmp-list) t)
-                 (?\C-g              ; Quit and restore buffers.
+                 (?\C-g                         ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
-                 ((or right ?\C-z)   ; Persistent action.
+                 ((or right ?\C-z)              ; Persistent action.
                   (ioccur-jump-without-quit) t)
-                 ((left ?\C-j)       ; Jump to candidate and kill search 
buffer.
+                 ((left ?\C-j)                  ; Jump to candidate and kill 
search buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
-                 (?\C-v              ; Scroll down.
+                 (?\C-v                         ; Scroll down.
                   (ioccur-scroll-other-window-down) t)
-                 ((?\C-t ?\M-v)              ; Scroll up.
+                 ((?\C-t ?\M-v)                 ; Scroll up.
                   (ioccur-scroll-other-window-up) t)
-                 (?\C-|              ; Toggle split window.
+                 (?\C-|                         ; Toggle split window.
                   (ioccur-split-window) t)
-                 (?\C-k              ; Kill input.
+                 (?\C-k                         ; Kill input.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
                   (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
-                 (?\C-y              ; Yank from `kill-ring'.
+                 (?\C-y                         ; Yank from `kill-ring'.
                   (setq initial-input (car kill-ring))
                   (unless (string= initial-input "")
                     (loop for char across initial-input
                        do (push char tmp-list)))
                   (setq ioccur-search-pattern initial-input) t)
-                 (?\C-w              ; Yank stuff at point.
+                 (?\C-w                         ; Yank stuff at point.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (unless old-yank-point (setq old-yank-point (point)))
@@ -466,13 +465,13 @@ Special commands:
                     (loop for char across initial-input
                        do (push char tmp-list)))
                   (setq ioccur-search-pattern initial-input) t)
-                 ((?\^\[ ?\M-p)      ; Precedent history elm.
+                 ((?\t ?\M-p)                   ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))
-                 ((?\^\[ ?\M-n)      ; Next history elm.
+                 ((backtab ?\M-n)                 ; Next history elm.
                   (start-timer)
                   (cycle-hist 1))
-                 (t                  ; Store character.
+                 (t                             ; Store character.
                   (start-timer)
                   (if (characterp char)
                       (push char tmp-list)
@@ -517,7 +516,6 @@ Special commands:
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.
-
 With a prefix arg search symbol at point (INITIAL-INPUT).
 
 While you are incremental searching, commands provided are:
@@ -527,14 +525,14 @@ C-p or <up>    precedent line.
 C-v and M-v    scroll up and down.
 C-z or <right> jump without quitting loop.
 C-j or <left>  jump and exit search buffer.
-RET or ESC     exit but don't quit search buffer.
+RET            exit but don't quit search buffer.
 DEL            remove last character entered.
 C-k            Kill current input.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
-M-p/n          Precedent and next `ioccur-history' element:
 C-down         Follow in other buffer.
 C-up           Follow in other buffer.
+M-p/n          Precedent and next `ioccur-history' element:
 
 M-p ,-->A B C D E F G H I---,
     |                       |
@@ -546,11 +544,11 @@ M-n ,-->I H G F E D C B A---,
 
 Special NOTE for terms:
 =======================
-  C-down/up in addition with M-n/p are bound to history.
+  tab/S-tab are bound to history.
   C-d/u are for following in other buffer.
   Use C-t to Scroll up.
  
-When you quit incremental search with RET or ESC, see `ioccur-mode'
+When you quit incremental search with RET, see `ioccur-mode'
 for commands provided in the search buffer."
   (interactive "P")
   (setq ioccur-exit-and-quit-p nil)

commit b5d38555e8a25b7e382ec97484b31e7add14ee6c
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Mar 26 19:21:16 2010 +0100

    (ioccur-split-window): new function to toggle split window.

diff --git a/ioccur.el b/ioccur.el
index 53cdc66..745a7ed 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -321,6 +321,19 @@ Special commands:
   (interactive)
   (ioccur-scroll -1))
 
+;;;###autoload
+(defun ioccur-split-window ()
+  "Toggle split window, vertically or horizontally."
+  (interactive)
+  (with-current-buffer ioccur-current-buffer
+    (let ((old-size (window-height)))
+      (delete-window)
+      (set-window-buffer
+       (select-window (if (= (window-height) old-size)
+                          (split-window-vertically)
+                          (split-window-horizontally)))
+       (get-buffer "*ioccur*")))))
+
 (defun ioccur-read-char-or-event (prompt)
   "Replace `read-key' when  not available."
   (if (fboundp 'read-key)
@@ -429,6 +442,8 @@ Special commands:
                   (ioccur-scroll-other-window-down) t)
                  ((?\C-t ?\M-v)              ; Scroll up.
                   (ioccur-scroll-other-window-up) t)
+                 (?\C-|              ; Toggle split window.
+                  (ioccur-split-window) t)
                  (?\C-k              ; Kill input.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer

commit 25f05c4d604211c0e8b5cbf61e3de2e1ff6accc6
Author: Thierry Volpiatto <address@hidden>
Date:   Fri Mar 26 16:56:44 2010 +0100

    Fix key bindings in terminal.

diff --git a/ioccur.el b/ioccur.el
index c04904f..53cdc66 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -73,7 +73,9 @@
   :type  'string)
 
 (defcustom ioccur-mode-line-string
-  " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Scroll, C-w:Yank tap"
+  (if (window-system)
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Follow, C-w:Yank tap"
+      " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-d/u:Follow, C-w:Yank tap")
   "*Documentation of `ioccur' prompt displayed in mode-line.
 Set it to nil to remove doc in mode-line."
   :group 'ioccur
@@ -393,7 +395,9 @@ Special commands:
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-search-pattern))))
-               (unless (or (equal char ?\M-p) (equal char ?\M-n))
+               (unless (or (equal char ?\M-p) (equal char ?\M-n)
+                           ;; Handle Meta in terms.
+                           (equal char ?\^\[) (equal char ?\^\[))
                  (setq start-hist nil) (setq cur-hist-elm (car 
ioccur-history)))
                (case char
                  ((down ?\C-n)       ; Next line.
@@ -402,12 +406,12 @@ Special commands:
                  ((up ?\C-p)         ; Precedent line.
                   (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
-                 (C-down             ; Scroll both windows down.
+                 ((?\C-d C-down)     ; Scroll both windows down.
                   (stop-timer)
                   (ioccur-scroll-down) t)
-                 (C-up               ; Scroll both windows up.
+                 ((?\C-u C-up)       ; Scroll both windows up.
                   (stop-timer) (ioccur-scroll-up) t)
-                 ((?\e ?\r)          ; RET or ESC break and exit code.
+                 (?\r                ; RET break and exit code.
                   (message nil) nil)
                  (?\d                ; Delete backward with DEL.
                   (start-timer)
@@ -423,7 +427,7 @@ Special commands:
                   (setq ioccur-exit-and-quit-p t) nil)
                  (?\C-v              ; Scroll down.
                   (ioccur-scroll-other-window-down) t)
-                 (?\M-v              ; Scroll up.
+                 ((?\C-t ?\M-v)              ; Scroll up.
                   (ioccur-scroll-other-window-up) t)
                  (?\C-k              ; Kill input.
                   (start-timer)
@@ -447,10 +451,10 @@ Special commands:
                     (loop for char across initial-input
                        do (push char tmp-list)))
                   (setq ioccur-search-pattern initial-input) t)
-                 (?\M-p              ; Precedent history elm.
+                 ((?\^\[ ?\M-p)      ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))
-                 (?\M-n              ; Next history elm.
+                 ((?\^\[ ?\M-n)      ; Next history elm.
                   (start-timer)
                   (cycle-hist 1))
                  (t                  ; Store character.
@@ -514,6 +518,8 @@ C-k            Kill current input.
 C-w            Yank stuff at point.
 C-g            quit and restore buffer.
 M-p/n          Precedent and next `ioccur-history' element:
+C-down         Follow in other buffer.
+C-up           Follow in other buffer.
 
 M-p ,-->A B C D E F G H I---,
     |                       |
@@ -523,6 +529,12 @@ M-n ,-->I H G F E D C B A---,
     |                       |
     `---A B C D E F G H I<--'
 
+Special NOTE for terms:
+=======================
+  C-down/up in addition with M-n/p are bound to history.
+  C-d/u are for following in other buffer.
+  Use C-t to Scroll up.
+ 
 When you quit incremental search with RET or ESC, see `ioccur-mode'
 for commands provided in the search buffer."
   (interactive "P")

commit af81c6a82094e99e9ccbb9ac664db3c203c214d9
Author: Chris Wanstrath <address@hidden>
Date:   Thu Mar 25 12:37:56 2010 -0700

    Highlight null. closes #4

diff --git a/coffee-mode.el b/coffee-mode.el
index f02a2eb..13456ba 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -243,7 +243,7 @@ print the compiled JavaScript."
 (defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
 
 ;; Booleans
-(defvar coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\)\\b")
+(defvar coffee-boolean-regexp 
"\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\)\\b")
 
 ;; Regular Expressions
 (defvar coffee-regexp-regexp "\\/.+?\\/")

commit 705b4687a23b151fc74415114e6c8df8d36a940c
Author: Chris Wanstrath <address@hidden>
Date:   Thu Mar 25 12:37:00 2010 -0700

    More realistic before-save-hook example

diff --git a/README.md b/README.md
index 4c3640b..570219c 100644
--- a/README.md
+++ b/README.md
@@ -211,8 +211,11 @@ Naturally. Example:
       ;; Riding edge.
       (setq coffee-command "~/dev/coffee"))
 
-      ;; Compile JS on every save.
-      (add-hook 'before-save-hook 'coffee-compile-file)
+      ;; Compile JS on every save, unless it's a Cakefile.
+      (add-hook 'before-save-hook
+          '(lambda ()
+             (when (not (string= (buffer-name) "Cakefile"))
+              (coffee-compile-file))))
 
     (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))
 

commit b7e600ded6264e9760576c1618ffea5885aae8e2
Merge: 3b0962d dc85f42
Author: Chris Wanstrath <address@hidden>
Date:   Thu Mar 25 12:35:05 2010 -0700

    Merge branch 'master' of github.com:defunkt/coffee-mode


commit 3b0962d41f1f0c0c835ae8971700124ed65ddd63
Author: Chris Wanstrath <address@hidden>
Date:   Thu Mar 25 12:34:59 2010 -0700

    Rename `args` variables to be more consistent.

diff --git a/README.md b/README.md
index 91fa003..4c3640b 100644
--- a/README.md
+++ b/README.md
@@ -205,9 +205,15 @@ Naturally. Example:
       ;; *Messages* spam
       (setq coffee-debug-mode t)
 
+      ;; Emacs key binding
+      (define-key coffee-mode-map [(meta r)] 'coffee-compile-buffer)
+
       ;; Riding edge.
       (setq coffee-command "~/dev/coffee"))
 
+      ;; Compile JS on every save.
+      (add-hook 'before-save-hook 'coffee-compile-file)
+
     (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))
 
 ## Configuration
@@ -249,14 +255,14 @@ path.
 
 Default: `"coffee"`
 
-### coffee-repl-args
+### coffee-args-repl
 
 The command line arguments to pass to `coffee-command' to start a
 REPL.
 
 Default: `'("-i")`
 
-### coffee-command-args
+### coffee-args-compile
 
 The command line arguments to pass to `coffee-command' to get it
 toprint the compiled JavaScript.
diff --git a/coffee-mode.el b/coffee-mode.el
index de69a86..471e5bd 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -96,12 +96,12 @@ path."
   :type 'string
   :group 'coffee)
 
-(defcustom coffee-repl-args '("-i")
+(defcustom coffee-args-repl '("-i")
   "The command line arguments to pass to `coffee-command' to start a REPL."
   :type 'list
   :group 'coffee)
 
-(defcustom coffee-command-args '("-s" "-p" "--no-wrap")
+(defcustom coffee-args-compile '("-s" "-p" "--no-wrap")
   "The command line arguments to pass to `coffee-command' to get it to
 print the compiled JavaScript."
   :type 'list
@@ -150,7 +150,7 @@ print the compiled JavaScript."
   (unless (comint-check-proc "*CoffeeREPL*")
     (set-buffer
      (apply 'make-comint "CoffeeREPL"
-            coffee-command nil coffee-repl-args)))
+            coffee-command nil coffee-args-repl)))
 
   (pop-to-buffer "*CoffeeScript*"))
 
@@ -303,7 +303,7 @@ For detail, see `comment-dwim'."
 
 (defun coffee-command-full ()
   "The full `coffee-command' complete with args."
-  (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
+  (mapconcat 'identity (append (list coffee-command) coffee-args-compile) " "))
 
 ;;
 ;; imenu support

commit d06361449c25068c68259582c84fd5070a45503e
Author: Sergei Lebedev <address@hidden>
Date:   Thu Mar 25 12:33:15 2010 -0700

    Fix hanging of `coffee-previous-indent` at start of buffer.

diff --git a/coffee-mode.el b/coffee-mode.el
index c28b21a..de69a86 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -457,8 +457,11 @@ For detail, see `comment-dwim'."
 
   (save-excursion
     (forward-line -1)
-    (while (coffee-line-empty-p) (forward-line -1))
-    (current-indentation)))
+    (if (bobp)
+        0
+      (progn
+        (while (coffee-line-empty-p) (forward-line -1))
+        (current-indentation)))))
 
 (defun coffee-line-empty-p ()
   "Is this line empty? Returns non-nil if so, nil if not."

commit dc85f42f3fc26a5b4815b51b961ea9223d4f6334
Author: tav <address@hidden>
Date:   Sun Mar 21 12:38:36 2010 +0800

    Added support for the shorthand::syntax for .prototype.

diff --git a/coffee-mode.el b/coffee-mode.el
index 83fa633..c57e206 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -230,6 +230,9 @@ print the compiled JavaScript."
 ;; Instance variables (implicit this)
 (defvar coffee-this-regexp "@\\w*\\|this")
 
+;; Prototype::access
+(defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| 
\\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
+
 ;; Assignment
 (defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
@@ -278,6 +281,7 @@ print the compiled JavaScript."
   ;; because otherwise the keyword "state" in the function
   ;; "state_entry" would be highlighted.
   `((,coffee-this-regexp . font-lock-variable-name-face)
+    (,coffee-prototype-regexp . font-lock-variable-name-face)
     (,coffee-assign-regexp . font-lock-type-face)
     (,coffee-regexp-regexp . font-lock-constant-face)
     (,coffee-boolean-regexp . font-lock-constant-face)

commit e3c21f85b4c55762b356a605a645afb4c474429d
Author: tav <address@hidden>
Date:   Sun Mar 21 12:22:46 2010 +0800

    Change so that the compiled buffer doesn't open in a new frame.

diff --git a/coffee-mode.el b/coffee-mode.el
index c28b21a..83fa633 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -181,7 +181,7 @@ print the compiled JavaScript."
                        (get-buffer-create coffee-compiled-buffer-name)
                        nil
                        "-s" "-p" "--no-wrap")
-  (switch-to-buffer-other-frame (get-buffer coffee-compiled-buffer-name))
+  (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
   (funcall coffee-js-mode)
   (beginning-of-buffer))
 

commit 587e5e26edbdaeb89ec6fa11f99cc91fc3fe11df
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 25 18:45:11 2010 +0100

    (ioccur-read-char-or-event): read-event need prompt, will be removed after 
emacs23.2.

diff --git a/ioccur.el b/ioccur.el
index 5be59db..c04904f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -324,7 +324,7 @@ Special commands:
   (if (fboundp 'read-key)
       (read-key prompt)
       (let* ((chr (condition-case nil (read-char prompt) (error nil)))
-             (evt (unless chr (read-event))))
+             (evt (unless chr (read-event prompt))))
         (or chr evt))))
 
 (defun ioccur-read-search-input (initial-input start-point)

commit 17676f047fc5bc7ea92d48beb0f52b1b86ce7f35
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 25 10:24:30 2010 +0100

    Add keys to ioccur-keymap, new function.
    
    (ioccur-jump-without-quit): new.

diff --git a/ioccur.el b/ioccur.el
index c56a82f..5be59db 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -41,6 +41,9 @@
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "q") 'ioccur-quit)
     (define-key map (kbd "RET") 'ioccur-jump-and-quit)
+    (define-key map (kbd "<left>") 'ioccur-jump-and-quit)
+    (define-key map (kbd "<right>") 'ioccur-jump-without-quit)
+    (define-key map (kbd "C-z") 'ioccur-jump-without-quit)
     (define-key map (kbd "<C-down>") 'ioccur-scroll-down)
     (define-key map (kbd "<C-up>") 'ioccur-scroll-up)
     (define-key map (kbd "C-v") 'ioccur-scroll-other-window-up)
@@ -282,6 +285,11 @@ Special commands:
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
 
+(defun ioccur-jump-without-quit ()
+  "Jump to line in `ioccur-current-buffer' without quiting."
+  (interactive)
+  (ioccur-jump) (other-window 1))
+
 (defun ioccur-scroll-other-window-down ()
   "Scroll other window down."
   (interactive)
@@ -410,7 +418,7 @@ Special commands:
                  (?\C-g              ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
                  ((or right ?\C-z)   ; Persistent action.
-                  (ioccur-jump) (other-window 1) t)
+                  (ioccur-jump-without-quit) t)
                  ((left ?\C-j)       ; Jump to candidate and kill search 
buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
                  (?\C-v              ; Scroll down.

commit eee2cc00ca2f0a21ffcea8d4d94610983e54868a
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Mar 24 09:18:31 2010 +0100

    (ioccur-read-search-input): Add C-y (yank).

diff --git a/ioccur.el b/ioccur.el
index 87c60ac..c56a82f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -423,6 +423,12 @@ Special commands:
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
                   (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
+                 (?\C-y              ; Yank from `kill-ring'.
+                  (setq initial-input (car kill-ring))
+                  (unless (string= initial-input "")
+                    (loop for char across initial-input
+                       do (push char tmp-list)))
+                  (setq ioccur-search-pattern initial-input) t)
                  (?\C-w              ; Yank stuff at point.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer

commit 3f77c647436d217a77d9b816262f79e0878d7923
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 23 10:18:04 2010 +0100

    (ioccur-search-delay): Change default value to 0.5, better in large buffers.

diff --git a/ioccur.el b/ioccur.el
index 2b0e5e9..87c60ac 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -59,7 +59,7 @@
   :group 'text)
 
 ;;; User variables.
-(defcustom ioccur-search-delay 0.2
+(defcustom ioccur-search-delay 0.5
   "*During incremental searching, display is updated all these seconds."
   :group 'ioccur
   :type  'integer)

commit d088d344f2e677cedf6012e7f382326858c4bcbd
Author: mooz <address@hidden>
Date:   Fri Mar 19 14:39:02 2010 +0900

    Refactored

diff --git a/js2-mode.el b/js2-mode.el
index e78c17b..52f356f 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9776,7 +9776,7 @@ returns nil."
                             (skip-chars-backward " \t}" (point-at-bol))
                             (or (bolp)
                                 (and (backward-word 1)
-                                     (or (skip-chars-backward " \t}" 
(point-at-bol)) t)
+                                     (skip-chars-backward " \t}" 
(point-at-bol))
                                      (bolp)
                                      (looking-at "[ \t}]*else[ \t]+if"))))
                           (looking-at js-possibly-braceless-keyword-re)

commit 29cb82362a4d833c1a153d84be01a89a4ba06fea
Author: mooz <address@hidden>
Date:   Fri Mar 19 13:18:09 2010 +0900

    Updated README

diff --git a/README.md b/README.md
index 553606b..2487c82 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,23 @@ Support for expression closure in property value
         fire: function () _fire()
     };
 
+Fixed the odd indentation of "else if" with no braces
+-----------------------------------------------------
+
+In original js2-mode.el,
+
+    if (foo)
+        return foo;
+    else if (bar)
+    return bar;      // here
+
+In this js2-mode.el,
+
+    if (foo)
+        return foo;
+    else if (bar)
+        return bar;  // fixed
+
 Bugs
 ====
 

commit 5ecf353bd16f909c5fe6e6145b3d8bf90935a143
Author: mooz <address@hidden>
Date:   Fri Mar 19 12:53:19 2010 +0900

    Oops.

diff --git a/js2-mode.el b/js2-mode.el
index c577c61..e78c17b 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9776,6 +9776,7 @@ returns nil."
                             (skip-chars-backward " \t}" (point-at-bol))
                             (or (bolp)
                                 (and (backward-word 1)
+                                     (or (skip-chars-backward " \t}" 
(point-at-bol)) t)
                                      (bolp)
                                      (looking-at "[ \t}]*else[ \t]+if"))))
                           (looking-at js-possibly-braceless-keyword-re)

commit 6a6d989d7eb2c16591be25d38bc8d6c1faf0c51c
Author: mooz <address@hidden>
Date:   Fri Mar 19 12:46:19 2010 +0900

    Fixed the odd indentation for the "else if" with no brace

diff --git a/js2-mode.el b/js2-mode.el
index 4fba8c8..c577c61 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -9774,7 +9774,10 @@ returns nil."
                      (when (looking-at "(") (backward-word 1))
                      (and (save-excursion
                             (skip-chars-backward " \t}" (point-at-bol))
-                            (bolp))
+                            (or (bolp)
+                                (and (backward-word 1)
+                                     (bolp)
+                                     (looking-at "[ \t}]*else[ \t]+if"))))
                           (looking-at js-possibly-braceless-keyword-re)
                           (not (js-end-of-do-while-loop-p))))))
         (save-excursion

commit 2252d3f680e633e33393273b9513d1ce019766d4
Author: mooz <address@hidden>
Date:   Mon Mar 15 21:46:13 2010 +0900

    Added document

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..553606b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+js2-mode
+========
+
+An improved JavaScript mode for GNU Emacs. Forked from 
<http://code.google.com/p/js2-mode/>.
+
+Install
+=======
+
+    $ git clone git://github.com/mooz/js2-mode.git
+    $ cd js2-mode
+    $ emacs --batch --eval '(byte-compile-file "js2-mode.el")'
+
+Then, place js2-mode.elc into your site-lisp directory.
+
+In you emacs config:
+
+    (autoload 'js2-mode "js2-mode" nil t)
+    (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+
+See <http://code.google.com/p/js2-mode/wiki/InstallationInstructions> for 
details.
+
+Differences between original js2-mode.el
+========================================
+
+Support for abbreviated destructuring assignments
+-------------------------------------------------
+
+    let {a, b}       = {a: 10, b: 20}; // Abbreviated   (Not supported in 
original js2-mode.el)
+    let {a: a, b: b} = {a: 10, b: 20}; // Same as above (Supported in original 
js2-mode.el)
+
+    (function ({responseText}) { /* */ })(xhr); // As the argument of function
+
+Support for expression closure in property value
+------------------------------------------------
+
+    let worker = {
+        get age() 20,
+        get sex() "male",
+        fire: function () _fire()
+    };
+
+Bugs
+====
+
+If you find problems, please report them to 
<http://github.com/mooz/js2-mode/issues>.

commit 9ac5418666c2b2271ea7ee56603292cfd446a5ee
Author: mooz <address@hidden>
Date:   Mon Mar 15 21:07:37 2010 +0900

    Added support for expression closure as the property value

diff --git a/js2-mode.el b/js2-mode.el
index 1960c22..4fba8c8 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7341,7 +7341,7 @@ Scanner should be initialized."
                           (- js2-ts-cursor (js2-node-pos fn-node)))
       (js2-node-add-children fn-node
                              (setf (js2-function-node-body fn-node)
-                                   (js2-parse-expr))))))
+                                   (js2-parse-expr t))))))
 
 (defun js2-parse-function-body (fn-node)
   (js2-must-match js2-LC "msg.no.brace.body"
@@ -8498,13 +8498,14 @@ If NODE is non-nil, it is the AST node associated with 
the symbol."
       (js2-define-new-symbol decl-type name node))
      (t (js2-code-bug)))))
 
-(defun js2-parse-expr ()
+(defun js2-parse-expr (&optional oneshot)
   (let* ((pn (js2-parse-assign-expr))
          (pos (js2-node-pos pn))
          left
          right
          op-pos)
-    (while (js2-match-token js2-COMMA)
+    (while (and (not oneshot)
+                (js2-match-token js2-COMMA))
       (setq op-pos (- js2-token-beg pos))  ; relative
       (if (= (js2-peek-token) js2-YIELD)
           (js2-report-error "msg.yield.parenthesized"))
@@ -9518,6 +9519,10 @@ JavaScript syntax is:
 
   { get foo() {...}, set foo(x) {...} }
 
+and expression closure style is also supported
+
+  { get foo() x, set foo(x) _x = x }
+
 POS is the start position of the `get' or `set' keyword.
 PROP is the `js2-name-node' representing the property name.
 GET-P is non-nil if the keyword was `get'."

commit 5a97ca2cb10e7e800a459670f5bc9b0237131cfe
Author: mooz <address@hidden>
Date:   Mon Mar 15 19:26:56 2010 +0900

    abbreviated destructuring bind as function params

diff --git a/js2-mode.el b/js2-mode.el
index 8cfb921..1960c22 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -7379,7 +7379,7 @@ Scanner should be initialized."
             (cond
              ;; destructuring param
              ((or (= tt js2-LB) (= tt js2-LC))
-              (push (js2-parse-primary-expr) params))
+              (push (js2-parse-primary-expr t) params))
              ;; simple name
              (t
               (js2-must-match js2-NAME "msg.no.parm")

commit 4e7c9b630407b125b572274dc3f493be487b7692
Author: mooz <address@hidden>
Date:   Mon Mar 15 19:21:39 2010 +0900

    added ignore list

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c531d98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.elc

commit baa41d7f8dc9ecdacc9107516f0ecf2afef9e80f
Author: mooz <address@hidden>
Date:   Mon Mar 15 19:07:32 2010 +0900

    Added support for abbreviated destructuring bind expression.

diff --git a/js2-mode.el b/js2-mode.el
index 581dd5f..8cfb921 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -8365,6 +8365,7 @@ Returns the parsed `js2-var-decl-node' expression node."
     ;; Example:
     ;; var foo = {a: 1, b: 2}, bar = [3, 4];
     ;; var {b: s2, a: s1} = foo, x = 6, y, [s3, s4] = bar;
+    ;; var {a, b} = baz;
     (while continue
       (setq destructuring nil
             name nil
@@ -8374,7 +8375,7 @@ Returns the parsed `js2-var-decl-node' expression node."
             init nil)
       (if (or (= tt js2-LB) (= tt js2-LC))
           ;; Destructuring assignment, e.g., var [a, b] = ...
-          (setq destructuring (js2-parse-primary-expr)
+          (setq destructuring (js2-parse-primary-expr t)
                 end (js2-node-end destructuring))
         ;; Simple variable name
         (when (js2-must-match js2-NAME "msg.bad.var")
@@ -9154,10 +9155,13 @@ For instance, @[expr], @*::[expr], or ns::[expr]."
                                           :rb (js2-relpos rb pos)))
       (js2-node-add-children pn namespace expr))))
 
-(defun js2-parse-primary-expr ()
+(defun js2-parse-primary-expr (&optional lhs)
   "Parses a literal (leaf) expression of some sort.
 Includes complex literals such as functions, object-literals,
-array-literals, array comprehensions and regular expressions."
+array-literals, array comprehensions and regular expressions.
+When `lhs' is t, we assume the given primary expression appeared in the left 
hand side
+and treat it in the somewhat special way.
+ex) {a, b} is permitted only when the `lhs' is t."
   (let ((tt-flagged (js2-next-flagged-token))
         pn      ; parent node  (usually return value)
         tt
@@ -9172,7 +9176,7 @@ array-literals, array comprehensions and regular 
expressions."
      ((= tt js2-LB)
       (js2-parse-array-literal))
      ((= tt js2-LC)
-      (js2-parse-object-literal))
+      (js2-parse-object-literal lhs))
      ((= tt js2-LET)
       (js2-parse-let js2-token-beg))
      ((= tt js2-LP)
@@ -9402,7 +9406,7 @@ Last token peeked should be the initial FOR."
       (js2-pop-scope))
     pn))
 
-(defun js2-parse-object-literal ()
+(defun js2-parse-object-literal (&optional lhs)
   (let ((pos js2-token-beg)
         tt
         elems
@@ -9412,11 +9416,11 @@ Last token peeked should be the initial FOR."
     (while continue
       (setq tt (js2-peek-token))
       (cond
-       ;; {foo: ...}, {'foo': ...}, {get foo() {...}}, or {set foo(x) {...}}
+       ;; {foo: ...}, {'foo': ...}, {foo, bar, ...}, {get foo() {...}}, or 
{set foo(x) {...}}
        ((or (js2-valid-prop-name-token tt)
             (= tt js2-STRING))
         (setq after-comma nil
-              result (js2-parse-named-prop tt))
+              result (js2-parse-named-prop tt lhs))
         (if (and (null result)
                  (not js2-recover-from-parse-errors))
             (setq continue nil)
@@ -9446,8 +9450,9 @@ Last token peeked should be the initial FOR."
     (apply #'js2-node-add-children result (js2-object-node-elems result))
     result))
 
-(defun js2-parse-named-prop (tt)
-  "Parse a name, string, or getter/setter object property."
+(defun js2-parse-named-prop (tt &optional lhs)
+  "Parse a name, string, or getter/setter object property.
+When `lhs' is t, forms like {a, b, c} will be permitted."
   (js2-consume-token)
   (let ((string-prop (and (= tt js2-STRING)
                           (make-js2-string-node)))
@@ -9456,18 +9461,29 @@ Last token peeked should be the initial FOR."
         (pend js2-token-end)
         (name (js2-create-name-node))
         (prop js2-ts-string))
-    (if (and (= tt js2-NAME)
-             (= (js2-peek-token) js2-NAME)
-             (or (string= prop "get")
-                 (string= prop "set")))
-        (progn
-          ;; getter/setter prop
-          (js2-consume-token)
-          (js2-set-face ppos pend 'font-lock-keyword-face 'record)  ; get/set
-          (js2-record-face 'font-lock-function-name-face)      ; for peeked 
name
-          (setq name (js2-create-name-node)) ; discard get/set & use peeked 
name
-          (js2-parse-getter-setter-prop ppos name (string= prop "get")))
-      ;; regular prop
+    (cond
+     ;; getter/setter prop
+     ((and (= tt js2-NAME)
+           (= (js2-peek-token) js2-NAME)
+           (or (string= prop "get")
+               (string= prop "set")))
+      (progn
+        (js2-consume-token)
+        (js2-set-face ppos pend 'font-lock-keyword-face 'record)  ; get/set
+        (js2-record-face 'font-lock-function-name-face)      ; for peeked name
+        (setq name (js2-create-name-node)) ; discard get/set & use peeked name
+        (js2-parse-getter-setter-prop ppos name (string= prop "get"))))
+     ;; abbreviated destructuring bind e.g., {a, b} = c;
+     ((and lhs
+           (= tt js2-NAME)
+           (let ((ctk (js2-peek-token)))
+             (or (= ctk js2-COMMA)
+                 (= ctk js2-RC)
+                 (js2-valid-prop-name-token ctk))))
+      (js2-set-face ppos pend 'font-lock-variable-name-face 'record)
+      name)
+     ;; regular prop
+     (t
       (prog1
           (setq expr (js2-parse-plain-property (or string-prop name)))
         (js2-set-face ppos pend
@@ -9475,7 +9491,7 @@ Last token peeked should be the initial FOR."
                            (js2-object-prop-node-right expr))
                           'font-lock-function-name-face
                         'font-lock-variable-name-face)
-                      'record)))))
+                      'record))))))
 
 (defun js2-parse-plain-property (prop)
   "Parse a non-getter/setter property in an object literal.

commit 5bfe8a369606d742cb50fc34a437ebe6f9630252
Author: mooz <address@hidden>
Date:   Mon Mar 15 19:05:37 2010 +0900

    Original js2-mode.el

diff --git a/js2-mode.el b/js2-mode.el
new file mode 100644
index 0000000..581dd5f
--- /dev/null
+++ b/js2-mode.el
@@ -0,0 +1,11367 @@
+;;; js2-mode.el --- an improved JavaScript editing mode
+
+;; Copyright (C) 2009  Free Software Foundation, Inc.
+
+;; Author:  Steve Yegge <address@hidden>
+;; Version:  See `js2-mode-version'
+;; Keywords:  languages, javascript
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This JavaScript editing mode supports:
+
+;;  - strict recognition of the Ecma-262 language standard
+;;  - support for most Rhino and SpiderMonkey extensions from 1.5 to 1.8
+;;  - parsing support for ECMAScript for XML (E4X, ECMA-357)
+;;  - accurate syntax highlighting using a recursive-descent parser
+;;  - on-the-fly reporting of syntax errors and strict-mode warnings
+;;  - undeclared-variable warnings using a configurable externs framework
+;;  - "bouncing" line indentation to choose among alternate indentation points
+;;  - smart line-wrapping within comments and strings
+;;  - code folding:
+;;    - show some or all function bodies as {...}
+;;    - show some or all block comments as /*...*/
+;;  - context-sensitive menu bar and popup menus
+;;  - code browsing using the `imenu' package
+;;  - typing helpers such as automatic insertion of matching braces/parens
+;;  - many customization options
+
+;; To customize how it works:
+;;   M-x customize-group RET js2-mode RET
+
+;; Notes:
+
+;; This mode includes a port of Mozilla Rhino's scanner, parser and
+;; symbol table.  Ideally it should stay in sync with Rhino, keeping
+;; `js2-mode' current as the EcmaScript language standard evolves.
+
+;; Unlike cc-engine based language modes, js2-mode's line-indentation is not
+;; customizable.  It is a surprising amount of work to support customizable
+;; indentation.  The current compromise is that the tab key lets you cycle 
among
+;; various likely indentation points, similar to the behavior of python-mode.
+
+;; This mode does not yet work with "multi-mode" modes such as `mmm-mode'
+;; and `mumamo', although it could be made to do so with some effort.
+;; This means that `js2-mode' is currently only useful for editing JavaScript
+;; files, and not for editing JavaScript within <script> tags or templates.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+
+(require 'imenu)
+(require 'cc-cmds)  ; for `c-fill-paragraph'
+
+(eval-and-compile
+  (require 'cc-mode)     ; (only) for `c-populate-syntax-table'
+  (require 'cc-langs)    ; it's here in Emacs 21...
+  (require 'cc-engine))  ; for `c-paragraph-start' et. al.
+
+;;; Externs (variables presumed to be defined by the host system)
+
+(defvar js2-ecma-262-externs
+  (mapcar 'symbol-name
+          '(Array Boolean Date Error EvalError Function Infinity
+          Math NaN Number Object RangeError ReferenceError RegExp
+          String SyntaxError TypeError URIError arguments
+          decodeURI decodeURIComponent encodeURI
+          encodeURIComponent escape eval isFinite isNaN
+          parseFloat parseInt undefined unescape))
+"Ecma-262 externs.  Included in `js2-externs' by default.")
+
+(defvar js2-browser-externs
+  (mapcar 'symbol-name
+          '(;; DOM level 1
+            Attr CDATASection CharacterData Comment DOMException
+            DOMImplementation Document DocumentFragment
+            DocumentType Element Entity EntityReference
+            ExceptionCode NamedNodeMap Node NodeList Notation
+            ProcessingInstruction Text
+
+            ;; DOM level 2
+            HTMLAnchorElement HTMLAppletElement HTMLAreaElement
+            HTMLBRElement HTMLBaseElement HTMLBaseFontElement
+            HTMLBodyElement HTMLButtonElement HTMLCollection
+            HTMLDListElement HTMLDirectoryElement HTMLDivElement
+            HTMLDocument HTMLElement HTMLFieldSetElement
+            HTMLFontElement HTMLFormElement HTMLFrameElement
+            HTMLFrameSetElement HTMLHRElement HTMLHeadElement
+            HTMLHeadingElement HTMLHtmlElement HTMLIFrameElement
+            HTMLImageElement HTMLInputElement HTMLIsIndexElement
+            HTMLLIElement HTMLLabelElement HTMLLegendElement
+            HTMLLinkElement HTMLMapElement HTMLMenuElement
+            HTMLMetaElement HTMLModElement HTMLOListElement
+            HTMLObjectElement HTMLOptGroupElement
+            HTMLOptionElement HTMLOptionsCollection
+            HTMLParagraphElement HTMLParamElement HTMLPreElement
+            HTMLQuoteElement HTMLScriptElement HTMLSelectElement
+            HTMLStyleElement HTMLTableCaptionElement
+            HTMLTableCellElement HTMLTableColElement
+            HTMLTableElement HTMLTableRowElement
+            HTMLTableSectionElement HTMLTextAreaElement
+            HTMLTitleElement HTMLUListElement
+
+            ;; DOM level 3
+            DOMConfiguration DOMError DOMException
+            DOMImplementationList DOMImplementationSource
+            DOMLocator DOMStringList NameList TypeInfo
+            UserDataHandler
+
+            ;; Window
+            alert confirm document java navigator prompt screen
+            self top
+
+            ;; W3C CSS
+            CSSCharsetRule CSSFontFace CSSFontFaceRule
+            CSSImportRule CSSMediaRule CSSPageRule
+            CSSPrimitiveValue CSSProperties CSSRule CSSRuleList
+            CSSStyleDeclaration CSSStyleRule CSSStyleSheet
+            CSSValue CSSValueList Counter DOMImplementationCSS
+            DocumentCSS DocumentStyle ElementCSSInlineStyle
+            LinkStyle MediaList RGBColor Rect StyleSheet
+            StyleSheetList ViewCSS
+
+            ;; W3C Event
+            EventListener EventTarget Event DocumentEvent UIEvent
+            MouseEvent MutationEvent KeyboardEvent
+
+            ;; W3C Range
+            DocumentRange Range RangeException
+
+            ;; W3C XML
+            XPathResult XMLHttpRequest))
+  "Browser externs.
+You can cause these to be included or excluded with the custom
+variable `js2-include-browser-externs'.")
+
+(defvar js2-rhino-externs
+  (mapcar 'symbol-name
+          '(Packages importClass importPackage com org java
+            ;; Global object (shell) externs
+            defineClass deserialize doctest gc help load
+            loadClass print quit readFile readUrl runCommand seal
+            serialize spawn sync toint32 version))
+  "Mozilla Rhino externs.
+Set `js2-include-rhino-externs' to t to include them.")
+
+(defvar js2-gears-externs
+  (mapcar 'symbol-name
+          '(
+            ;; TODO(stevey):  add these
+            ))
+  "Google Gears externs.
+Set `js2-include-gears-externs' to t to include them.")
+
+;;; Variables
+
+(defvar js2-emacs22 (>= emacs-major-version 22))
+
+(defcustom js2-highlight-level 2
+  "Amount of syntax highlighting to perform.
+0 or a negative value means do no highlighting.
+1 adds basic syntax highlighting.
+2 adds highlighting of some Ecma built-in properties.
+3 adds highlighting of many Ecma built-in functions."
+  :group 'js2-mode
+  :type '(choice (const :tag "None" 0)
+                 (const :tag "Basic" 1)
+                 (const :tag "Include Properties" 2)
+                 (const :tag "Include Functions" 3)))
+
+(defvar js2-mode-dev-mode-p nil
+  "Non-nil if running in development mode.  Normally nil.")
+
+(defgroup js2-mode nil
+  "An improved JavaScript mode."
+  :group 'languages)
+
+(defcustom js2-basic-offset (if (and (boundp 'c-basic-offset)
+                                     (numberp c-basic-offset))
+                                c-basic-offset
+                              4)
+  "Number of spaces to indent nested statements.
+Similar to `c-basic-offset'."
+  :group 'js2-mode
+  :type 'integer)
+(make-variable-buffer-local 'js2-basic-offset)
+
+;; TODO(stevey):  move this code into a separate minor mode.
+(defcustom js2-mirror-mode nil
+  "Non-nil to insert closing brackets, parens, etc. automatically."
+  :group 'js2-mode
+  :type 'boolean)
+
+(defcustom js2-auto-indent-p nil
+  "Automatic indentation with punctuation characters.
+If non-nil, the current line is indented when certain punctuations
+are inserted."
+  :group 'js2-mode
+  :type 'boolean)
+
+(defcustom js2-bounce-indent-p nil
+  "Non-nil to have indent-line function choose among alternatives.
+If nil, the indent-line function will indent to a predetermined column
+based on heuristic guessing.  If non-nil, then if the current line is
+already indented to that predetermined column, indenting will choose
+another likely column and indent to that spot.  Repeated invocation of
+the indent-line function will cycle among the computed alternatives.
+See the function `js2-bounce-indent' for details."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-indent-on-enter-key nil
+  "Non-nil to have Enter/Return key indent the line.
+This is unusual for Emacs modes but common in IDEs like Eclipse."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-enter-indents-newline nil
+  "Non-nil to have Enter/Return key indent the newly-inserted line.
+This is unusual for Emacs modes but common in IDEs like Eclipse."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-rebind-eol-bol-keys t
+  "Non-nil to rebind `beginning-of-line' and `end-of-line' keys.
+If non-nil, bounce between bol/eol and first/last non-whitespace char."
+  :group 'js2-mode
+  :type 'boolean)
+
+(defcustom js2-electric-keys '("{" "}" "(" ")" "[" "]" ":" ";" "," "*")
+  "Keys that auto-indent when `js2-auto-indent-p' is non-nil.
+Each value in the list is passed to `define-key'."
+  :type 'list
+  :group 'js2-mode)
+
+(defcustom js2-idle-timer-delay 0.2
+  "Delay in secs before re-parsing after user makes changes.
+Multiplied by `js2-dynamic-idle-timer-adjust', which see."
+  :type 'number
+  :group 'js2-mode)
+(make-variable-buffer-local 'js2-idle-timer-delay)
+
+(defcustom js2-dynamic-idle-timer-adjust 0
+  "Positive to adjust `js2-idle-timer-delay' based on file size.
+The idea is that for short files, parsing is faster so we can be
+more responsive to user edits without interfering with editing.
+The buffer length in characters (typically bytes) is divided by
+this value and used to multiply `js2-idle-timer-delay' for the
+buffer.  For example, a 21k file and 10k adjust yields 21k/10k
+== 2, so js2-idle-timer-delay is multiplied by 2.
+If `js2-dynamic-idle-timer-adjust' is 0 or negative,
+`js2-idle-timer-delay' is not dependent on the file size."
+  :type 'number
+  :group 'js2-mode)
+
+(defcustom js2-mode-escape-quotes t
+  "Non-nil to disable automatic quote-escaping inside strings."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-mode-squeeze-spaces t
+  "Non-nil to normalize whitespace when filling in comments.
+Multiple runs of spaces are converted to a single space."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-mode-show-parse-errors t
+  "True to highlight parse errors."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-mode-show-strict-warnings t
+  "Non-nil to emit Ecma strict-mode warnings.
+Some of the warnings can be individually disabled by other flags,
+even if this flag is non-nil."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-trailing-comma-warning t
+  "Non-nil to warn about trailing commas in array literals.
+Ecma-262 forbids them, but many browsers permit them.  IE is the
+big exception, and can produce bugs if you have trailing commas."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-missing-semi-warning t
+  "Non-nil to warn about semicolon auto-insertion after statement.
+Technically this is legal per Ecma-262, but some style guides disallow
+depending on it."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-missing-semi-one-line-override nil
+  "Non-nil to permit missing semicolons in one-line functions.
+In one-liner functions such as `function identity(x) {return x}'
+people often omit the semicolon for a cleaner look.  If you are
+such a person, you can suppress the missing-semicolon warning
+by setting this variable to t."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-inconsistent-return-warning t
+  "Non-nil to warn about mixing returns with value-returns.
+It's perfectly legal to have a `return' and a `return foo' in the
+same function, but it's often an indicator of a bug, and it also
+interferes with type inference (in systems that support it.)"
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-cond-assign-warning t
+  "Non-nil to warn about expressions like if (a = b).
+This often should have been '==' instead of '='.  If the warning
+is enabled, you can suppress it on a per-expression basis by
+parenthesizing the expression, e.g. if ((a = b)) ..."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-cond-assign-warning t
+  "Non-nil to warn about expressions like if (a = b).
+This often should have been '==' instead of '='.  If the warning
+is enabled, you can suppress it on a per-expression basis by
+parenthesizing the expression, e.g. if ((a = b)) ..."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-var-redeclaration-warning t
+  "Non-nil to warn about redeclaring variables in a script or function."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-strict-var-hides-function-arg-warning t
+  "Non-nil to warn about a var decl hiding a function argument."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-skip-preprocessor-directives nil
+  "Non-nil to treat lines beginning with # as comments.
+Useful for viewing Mozilla JavaScript source code."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-language-version 180
+  "Configures what JavaScript language version to recognize.
+Currently versions 150, 160, 170 and 180 are supported, corresponding
+to JavaScript 1.5, 1.6, 1.7 and 1.8, respectively.  In a nutshell,
+1.6 adds E4X support, 1.7 adds let, yield, and Array comprehensions,
+and 1.8 adds function closures."
+  :type 'integer
+  :group 'js2-mode)
+
+(defcustom js2-allow-keywords-as-property-names t
+  "If non-nil, you can use JavaScript keywords as object property names.
+Examples:
+
+  var foo = {int: 5, while: 6, continue: 7};
+  foo.return = 8;
+
+Ecma-262 forbids this syntax, but many browsers support it."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-instanceof-has-side-effects nil
+  "If non-nil, treats the instanceof operator as having side effects.
+This is useful for xulrunner apps."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-cleanup-whitespace nil
+  "Non-nil to invoke `delete-trailing-whitespace' before saves."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-move-point-on-right-click t
+  "Non-nil to move insertion point when you right-click.
+This makes right-click context menu behavior a bit more intuitive,
+since menu operations generally apply to the point.  The exception
+is if there is a region selection, in which case the point does -not-
+move, so cut/copy/paste etc. can work properly.
+
+Note that IntelliJ moves the point, and Eclipse leaves it alone,
+so this behavior is customizable."
+  :group 'js2-mode
+  :type 'boolean)
+
+(defcustom js2-allow-rhino-new-expr-initializer t
+  "Non-nil to support a Rhino's experimental syntactic construct.
+
+Rhino supports the ability to follow a `new' expression with an object
+literal, which is used to set additional properties on the new object
+after calling its constructor.  Syntax:
+
+  new <expr> [ ( arglist ) ] [initializer]
+
+Hence, this expression:
+
+  new Object {a: 1, b: 2}
+
+results in an Object with properties a=1 and b=2.  This syntax is
+apparently not configurable in Rhino - it's currently always enabled,
+as of Rhino version 1.7R2."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-allow-member-expr-as-function-name nil
+  "Non-nil to support experimental Rhino syntax for function names.
+
+Rhino supports an experimental syntax configured via the Rhino Context
+setting `allowMemberExprAsFunctionName'.  The experimental syntax is:
+
+  function <member-expr> ( [ arg-list ] ) { <body> }
+
+Where member-expr is a non-parenthesized 'member expression', which
+is anything at the grammar level of a new-expression or lower, meaning
+any expression that does not involve infix or unary operators.
+
+When <member-expr> is not a simple identifier, then it is syntactic
+sugar for assigning the anonymous function to the <member-expr>.  Hence,
+this code:
+
+  function a.b().c[2] (x, y) { ... }
+
+is rewritten as:
+
+  a.b().c[2] = function(x, y) {...}
+
+which doesn't seem particularly useful, but Rhino permits it."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defvar js2-mode-version 20090727
+  "Release number for `js2-mode'.")
+
+;; scanner variables
+
+(defmacro js2-deflocal (name value &optional comment)
+  "Define a buffer-local variable NAME with VALUE and COMMENT."
+  `(progn
+     (defvar ,name ,value ,comment)
+     (make-variable-buffer-local ',name)))
+
+;; We record the start and end position of each token.
+(js2-deflocal js2-token-beg 1)
+(js2-deflocal js2-token-end -1)
+
+(defvar js2-EOF_CHAR -1
+  "Represents end of stream.  Distinct from js2-EOF token type.")
+
+;; I originally used symbols to represent tokens, but Rhino uses
+;; ints and then sets various flag bits in them, so ints it is.
+;; The upshot is that we need a `js2-' prefix in front of each name.
+(defvar js2-ERROR -1)
+(defvar js2-EOF 0)
+(defvar js2-EOL 1)
+(defvar js2-ENTERWITH 2)       ; begin interpreter bytecodes
+(defvar js2-LEAVEWITH 3)
+(defvar js2-RETURN 4)
+(defvar js2-GOTO 5)
+(defvar js2-IFEQ 6)
+(defvar js2-IFNE 7)
+(defvar js2-SETNAME 8)
+(defvar js2-BITOR 9)
+(defvar js2-BITXOR 10)
+(defvar js2-BITAND 11)
+(defvar js2-EQ 12)
+(defvar js2-NE 13)
+(defvar js2-LT 14)
+(defvar js2-LE 15)
+(defvar js2-GT 16)
+(defvar js2-GE 17)
+(defvar js2-LSH 18)
+(defvar js2-RSH 19)
+(defvar js2-URSH 20)
+(defvar js2-ADD 21)            ; infix plus
+(defvar js2-SUB 22)            ; infix minus
+(defvar js2-MUL 23)
+(defvar js2-DIV 24)
+(defvar js2-MOD 25)
+(defvar js2-NOT 26)
+(defvar js2-BITNOT 27)
+(defvar js2-POS 28)            ; unary plus
+(defvar js2-NEG 29)            ; unary minus
+(defvar js2-NEW 30)
+(defvar js2-DELPROP 31)
+(defvar js2-TYPEOF 32)
+(defvar js2-GETPROP 33)
+(defvar js2-GETPROPNOWARN 34)
+(defvar js2-SETPROP 35)
+(defvar js2-GETELEM 36)
+(defvar js2-SETELEM 37)
+(defvar js2-CALL 38)
+(defvar js2-NAME 39)           ; an identifier
+(defvar js2-NUMBER 40)
+(defvar js2-STRING 41)
+(defvar js2-NULL 42)
+(defvar js2-THIS 43)
+(defvar js2-FALSE 44)
+(defvar js2-TRUE 45)
+(defvar js2-SHEQ 46)           ; shallow equality (===)
+(defvar js2-SHNE 47)           ; shallow inequality (!==)
+(defvar js2-REGEXP 48)
+(defvar js2-BINDNAME 49)
+(defvar js2-THROW 50)
+(defvar js2-RETHROW 51)        ; rethrow caught exception: catch (e if ) uses 
it
+(defvar js2-IN 52)
+(defvar js2-INSTANCEOF 53)
+(defvar js2-LOCAL_LOAD 54)
+(defvar js2-GETVAR 55)
+(defvar js2-SETVAR 56)
+(defvar js2-CATCH_SCOPE 57)
+(defvar js2-ENUM_INIT_KEYS 58)
+(defvar js2-ENUM_INIT_VALUES 59)
+(defvar js2-ENUM_INIT_ARRAY 60)
+(defvar js2-ENUM_NEXT 61)
+(defvar js2-ENUM_ID 62)
+(defvar js2-THISFN 63)
+(defvar js2-RETURN_RESULT 64)  ; to return previously stored return result
+(defvar js2-ARRAYLIT 65)       ; array literal
+(defvar js2-OBJECTLIT 66)      ; object literal
+(defvar js2-GET_REF 67)        ; *reference
+(defvar js2-SET_REF 68)        ; *reference = something
+(defvar js2-DEL_REF 69)        ; delete reference
+(defvar js2-REF_CALL 70)       ; f(args) = something or f(args)++
+(defvar js2-REF_SPECIAL 71)    ; reference for special properties like __proto
+(defvar js2-YIELD 72)          ; JS 1.7 yield pseudo keyword
+
+;; XML support
+(defvar js2-DEFAULTNAMESPACE 73)
+(defvar js2-ESCXMLATTR 74)
+(defvar js2-ESCXMLTEXT 75)
+(defvar js2-REF_MEMBER 76)     ; Reference for address@hidden, x..y etc.
+(defvar js2-REF_NS_MEMBER 77)  ; Reference for x.ns::y, x..ns::y etc.
+(defvar js2-REF_NAME 78)       ; Reference for @y, @[y] etc.
+(defvar js2-REF_NS_NAME 79)    ; Reference for ns::y, @ns::address@hidden etc.
+
+(defvar js2-first-bytecode js2-ENTERWITH)
+(defvar js2-last-bytecode js2-REF_NS_NAME)
+
+(defvar js2-TRY 80)
+(defvar js2-SEMI 81)           ; semicolon
+(defvar js2-LB 82)             ; left and right brackets
+(defvar js2-RB 83)
+(defvar js2-LC 84)             ; left and right curly-braces
+(defvar js2-RC 85)
+(defvar js2-LP 86)             ; left and right parens
+(defvar js2-RP 87)
+(defvar js2-COMMA 88)          ; comma operator
+
+(defvar js2-ASSIGN 89)         ; simple assignment (=)
+(defvar js2-ASSIGN_BITOR 90)   ; |=
+(defvar js2-ASSIGN_BITXOR 91)  ; ^=
+(defvar js2-ASSIGN_BITAND 92)  ; &=
+(defvar js2-ASSIGN_LSH 93)     ; <<=
+(defvar js2-ASSIGN_RSH 94)     ; >>=
+(defvar js2-ASSIGN_URSH 95)    ; >>>=
+(defvar js2-ASSIGN_ADD 96)     ; +=
+(defvar js2-ASSIGN_SUB 97)     ; -=
+(defvar js2-ASSIGN_MUL 98)     ; *=
+(defvar js2-ASSIGN_DIV 99)     ; /=
+(defvar js2-ASSIGN_MOD 100)    ; %=
+
+(defvar js2-first-assign js2-ASSIGN)
+(defvar js2-last-assign js2-ASSIGN_MOD)
+
+(defvar js2-HOOK 101)          ; conditional (?:)
+(defvar js2-COLON 102)
+(defvar js2-OR 103)            ; logical or (||)
+(defvar js2-AND 104)           ; logical and (&&)
+(defvar js2-INC 105)           ; increment/decrement (++ --)
+(defvar js2-DEC 106)
+(defvar js2-DOT 107)           ; member operator (.)
+(defvar js2-FUNCTION 108)      ; function keyword
+(defvar js2-EXPORT 109)        ; export keyword
+(defvar js2-IMPORT 110)        ; import keyword
+(defvar js2-IF 111)            ; if keyword
+(defvar js2-ELSE 112)          ; else keyword
+(defvar js2-SWITCH 113)        ; switch keyword
+(defvar js2-CASE 114)          ; case keyword
+(defvar js2-DEFAULT 115)       ; default keyword
+(defvar js2-WHILE 116)         ; while keyword
+(defvar js2-DO 117)            ; do keyword
+(defvar js2-FOR 118)           ; for keyword
+(defvar js2-BREAK 119)         ; break keyword
+(defvar js2-CONTINUE 120)      ; continue keyword
+(defvar js2-VAR 121)           ; var keyword
+(defvar js2-WITH 122)          ; with keyword
+(defvar js2-CATCH 123)         ; catch keyword
+(defvar js2-FINALLY 124)       ; finally keyword
+(defvar js2-VOID 125)          ; void keyword
+(defvar js2-RESERVED 126)      ; reserved keywords
+
+(defvar js2-EMPTY 127)
+
+;; Types used for the parse tree - never returned by scanner.
+
+(defvar js2-BLOCK 128)         ; statement block
+(defvar js2-LABEL 129)         ; label
+(defvar js2-TARGET 130)
+(defvar js2-LOOP 131)
+(defvar js2-EXPR_VOID 132)     ; expression statement in functions
+(defvar js2-EXPR_RESULT 133)   ; expression statement in scripts
+(defvar js2-JSR 134)
+(defvar js2-SCRIPT 135)        ; top-level node for entire script
+(defvar js2-TYPEOFNAME 136)    ; for typeof(simple-name)
+(defvar js2-USE_STACK 137)
+(defvar js2-SETPROP_OP 138)    ; x.y op= something
+(defvar js2-SETELEM_OP 139)    ; x[y] op= something
+(defvar js2-LOCAL_BLOCK 140)
+(defvar js2-SET_REF_OP 141)    ; *reference op= something
+
+;; For XML support:
+(defvar js2-DOTDOT 142)        ; member operator (..)
+(defvar js2-COLONCOLON 143)    ; namespace::name
+(defvar js2-XML 144)           ; XML type
+(defvar js2-DOTQUERY 145)      ; .() -- e.g., x.emps.emp.(name == "terry")
+(defvar js2-XMLATTR 146)       ; @
+(defvar js2-XMLEND 147)
+
+;; Optimizer-only tokens
+(defvar js2-TO_OBJECT 148)
+(defvar js2-TO_DOUBLE 149)
+
+(defvar js2-GET 150)           ; JS 1.5 get pseudo keyword
+(defvar js2-SET 151)           ; JS 1.5 set pseudo keyword
+(defvar js2-LET 152)           ; JS 1.7 let pseudo keyword
+(defvar js2-CONST 153)
+(defvar js2-SETCONST 154)
+(defvar js2-SETCONSTVAR 155)
+(defvar js2-ARRAYCOMP 156)
+(defvar js2-LETEXPR 157)
+(defvar js2-WITHEXPR 158)
+(defvar js2-DEBUGGER 159)
+
+(defvar js2-COMMENT 160)
+(defvar js2-ENUM 161)  ; for "enum" reserved word
+
+(defconst js2-num-tokens (1+ js2-ENUM))
+
+(defconst js2-debug-print-trees nil)
+
+;; Rhino accepts any string or stream as input.  Emacs character
+;; processing works best in buffers, so we'll assume the input is a
+;; buffer.  JavaScript strings can be copied into temp buffers before
+;; scanning them.
+
+;; Buffer-local variables yield much cleaner code than using `defstruct'.
+;; They're the Emacs equivalent of instance variables, more or less.
+
+(js2-deflocal js2-ts-dirty-line nil
+  "Token stream buffer-local variable.
+Indicates stuff other than whitespace since start of line.")
+
+(js2-deflocal js2-ts-regexp-flags nil
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-string ""
+  "Token stream buffer-local variable.
+Last string scanned.")
+
+(js2-deflocal js2-ts-number nil
+  "Token stream buffer-local variable.
+Last literal number scanned.")
+
+(js2-deflocal js2-ts-hit-eof nil
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-line-start 0
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-lineno 1
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-line-end-char -1
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-cursor 1  ; emacs buffers are 1-indexed
+  "Token stream buffer-local variable.
+Current scan position.")
+
+(js2-deflocal js2-ts-is-xml-attribute nil
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-xml-is-tag-content nil
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-xml-open-tags-count 0
+  "Token stream buffer-local variable.")
+
+(js2-deflocal js2-ts-string-buffer nil
+  "Token stream buffer-local variable.
+List of chars built up while scanning various tokens.")
+
+(js2-deflocal js2-ts-comment-type nil
+  "Token stream buffer-local variable.")
+
+;;; Parser variables
+
+(js2-deflocal js2-parsed-errors nil
+  "List of errors produced during scanning/parsing.")
+
+(js2-deflocal js2-parsed-warnings nil
+  "List of warnings produced during scanning/parsing.")
+
+(js2-deflocal js2-recover-from-parse-errors t
+  "Non-nil to continue parsing after a syntax error.
+
+In recovery mode, the AST will be built in full, and any error
+nodes will be flagged with appropriate error information.  If
+this flag is nil, a syntax error will result in an error being
+signaled.
+
+The variable is automatically buffer-local, because different
+modes that use the parser will need different settings.")
+
+(js2-deflocal js2-parse-hook nil
+  "List of callbacks for receiving parsing progress.")
+
+(defvar js2-parse-finished-hook nil
+  "List of callbacks to notify when parsing finishes.
+Not called if parsing was interrupted.")
+
+(js2-deflocal js2-is-eval-code nil
+  "True if we're evaluating code in a string.
+If non-nil, the tokenizer will record the token text, and the AST nodes
+will record their source text.  Off by default for IDE modes, since the
+text is available in the buffer.")
+
+(defvar js2-parse-ide-mode t
+  "Non-nil if the parser is being used for `js2-mode'.
+If non-nil, the parser will set text properties for fontification
+and the syntax table.  The value should be nil when using the
+parser as a frontend to an interpreter or byte compiler.")
+
+;;; Parser instance variables (buffer-local vars for js2-parse)
+
+(defconst js2-clear-ti-mask #xFFFF
+  "Mask to clear token information bits.")
+
+(defconst js2-ti-after-eol (lsh 1 16)
+  "Flag:  first token of the source line.")
+
+(defconst js2-ti-check-label (lsh 1 17)
+  "Flag:  indicates to check for label.")
+
+;; Inline Rhino's CompilerEnvirons vars as buffer-locals.
+
+(js2-deflocal js2-compiler-generate-debug-info t)
+(js2-deflocal js2-compiler-use-dynamic-scope nil)
+(js2-deflocal js2-compiler-reserved-keywords-as-identifier nil)
+(js2-deflocal js2-compiler-xml-available t)
+(js2-deflocal js2-compiler-optimization-level 0)
+(js2-deflocal js2-compiler-generating-source t)
+(js2-deflocal js2-compiler-strict-mode nil)
+(js2-deflocal js2-compiler-report-warning-as-error nil)
+(js2-deflocal js2-compiler-generate-observer-count nil)
+(js2-deflocal js2-compiler-activation-names nil)
+
+;; SKIP:  sourceURI
+
+;; There's a compileFunction method in Context.java - may need it.
+(js2-deflocal js2-called-by-compile-function nil
+  "True if `js2-parse' was called by `js2-compile-function'.
+Will only be used when we finish implementing the interpreter.")
+
+;; SKIP:  ts  (we just call `js2-init-scanner' and use its vars)
+
+(js2-deflocal js2-current-flagged-token js2-EOF)
+(js2-deflocal js2-current-token js2-EOF)
+
+;; SKIP:  node factory - we're going to just call functions directly,
+;; and eventually go to a unified AST format.
+
+(js2-deflocal js2-nesting-of-function 0)
+
+(js2-deflocal js2-recorded-assignments nil
+  "Tracks assignments found during parsing.")
+
+(defcustom js2-global-externs nil
+  "A list of any extern names you'd like to consider always declared.
+This list is global and is used by all js2-mode files.
+You can create buffer-local externs list using `js2-additional-externs'.
+
+There is also a buffer-local variable `js2-default-externs',
+which is initialized by default to include the Ecma-262 externs
+and the standard browser externs.  The three lists are all
+checked during highlighting."
+  :type 'list
+  :group 'js2-mode)
+
+(js2-deflocal js2-default-externs nil
+  "Default external declarations.
+
+These are currently only used for highlighting undeclared variables,
+which only worries about top-level (unqualified) references.
+As js2-mode's processing improves, we will flesh out this list.
+
+The initial value is set to `js2-ecma-262-externs', unless you
+have set `js2-include-browser-externs', in which case the browser
+externs are also included.
+
+See `js2-additional-externs' for more information.")
+
+(defcustom js2-include-browser-externs t
+  "Non-nil to include browser externs in the master externs list.
+If you work on JavaScript files that are not intended for browsers,
+such as Mozilla Rhino server-side JavaScript, set this to nil.
+You can always include them on a per-file basis by calling
+`js2-add-browser-externs' from a function on `js2-mode-hook'.
+
+See `js2-additional-externs' for more information about externs."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-include-rhino-externs t
+  "Non-nil to include Mozilla Rhino externs in the master externs list.
+See `js2-additional-externs' for more information about externs."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-include-gears-externs t
+  "Non-nil to include Google Gears externs in the master externs list.
+See `js2-additional-externs' for more information about externs."
+  :type 'boolean
+  :group 'js2-mode)
+
+(js2-deflocal js2-additional-externs nil
+  "A buffer-local list of additional external declarations.
+It is used to decide whether variables are considered undeclared
+for purposes of highlighting.
+
+Each entry is a lisp string.  The string should be the fully qualified
+name of an external entity.  All externs should be added to this list,
+so that as js2-mode's processing improves it can take advantage of them.
+
+You may want to declare your externs in three ways.
+First, you can add externs that are valid for all your JavaScript files.
+You should probably do this by adding them to `js2-global-externs', which
+is a global list used for all js2-mode files.
+
+Next, you can add a function to `js2-mode-hook' that adds additional
+externs appropriate for the specific file, perhaps based on its path.
+These should go in `js2-additional-externs', which is buffer-local.
+
+Finally, you can add a function to `js2-post-parse-callbacks',
+which is called after parsing completes, and `root' is bound to
+the root of the parse tree.  At this stage you can set up an AST
+node visitor using `js2-visit-ast' and examine the parse tree
+for specific import patterns that may imply the existence of
+other externs, possibly tied to your build system.  These should also
+be added to `js2-additional-externs'.
+
+Your post-parse callback may of course also use the simpler and
+faster (but perhaps less robust) approach of simply scanning the
+buffer text for your imports, using regular expressions.")
+
+;; SKIP:  decompiler
+;; SKIP:  encoded-source
+
+;;; The following variables are per-function and should be saved/restored
+;;; during function parsing...
+
+(js2-deflocal js2-current-script-or-fn nil)
+(js2-deflocal js2-current-scope nil)
+(js2-deflocal js2-nesting-of-with 0)
+(js2-deflocal js2-label-set nil
+  "An alist mapping label names to nodes.")
+
+(js2-deflocal js2-loop-set nil)
+(js2-deflocal js2-loop-and-switch-set nil)
+(js2-deflocal js2-has-return-value nil)
+(js2-deflocal js2-end-flags 0)
+
+;;; ...end of per function variables
+
+;; Without 2-token lookahead, labels are a problem.
+;; These vars store the token info of the last matched name,
+;; iff it wasn't the last matched token.  Only valid in some contexts.
+(defvar js2-prev-name-token-start nil)
+(defvar js2-prev-name-token-string nil)
+
+(defsubst js2-save-name-token-data (pos name)
+  (setq js2-prev-name-token-start pos
+        js2-prev-name-token-string name))
+
+;; These flags enumerate the possible ways a statement/function can
+;; terminate. These flags are used by endCheck() and by the Parser to
+;; detect inconsistent return usage.
+;;
+;; END_UNREACHED is reserved for code paths that are assumed to always be
+;; able to execute (example: throw, continue)
+;;
+;; END_DROPS_OFF indicates if the statement can transfer control to the
+;; next one. Statement such as return dont. A compound statement may have
+;; some branch that drops off control to the next statement.
+;;
+;; END_RETURNS indicates that the statement can return (without arguments)
+;; END_RETURNS_VALUE indicates that the statement can return a value.
+;;
+;; A compound statement such as
+;; if (condition) {
+;;   return value;
+;; }
+;; Will be detected as (END_DROPS_OFF | END_RETURN_VALUE) by endCheck()
+
+(defconst js2-end-unreached     #x0)
+(defconst js2-end-drops-off     #x1)
+(defconst js2-end-returns       #x2)
+(defconst js2-end-returns-value #x4)
+(defconst js2-end-yields        #x8)
+
+;; Rhino awkwardly passes a statementLabel parameter to the
+;; statementHelper() function, the main statement parser, which
+;; is then used by quite a few of the sub-parsers.  We just make
+;; it a buffer-local variable and make sure it's cleaned up properly.
+(js2-deflocal js2-labeled-stmt nil)  ; type `js2-labeled-stmt-node'
+
+;; Similarly, Rhino passes an inForInit boolean through about half
+;; the expression parsers.  We use a dynamically-scoped variable,
+;; which makes it easier to funcall the parsers individually without
+;; worrying about whether they take the parameter or not.
+(js2-deflocal js2-in-for-init nil)
+(js2-deflocal js2-temp-name-counter 0)
+(js2-deflocal js2-parse-stmt-count 0)
+
+(defsubst js2-get-next-temp-name ()
+  (format "$%d" (incf js2-temp-name-counter)))
+
+(defvar js2-parse-interruptable-p t
+  "Set this to nil to force parse to continue until finished.
+This will mostly be useful for interpreters.")
+
+(defvar js2-statements-per-pause 50
+  "Pause after this many statements to check for user input.
+If user input is pending, stop the parse and discard the tree.
+This makes for a smoother user experience for large files.
+You may have to wait a second or two before the highlighting
+and error-reporting appear, but you can always type ahead if
+you wish.  This appears to be more or less how Eclipse, IntelliJ
+and other editors work.")
+
+(js2-deflocal js2-record-comments t
+  "Instructs the scanner to record comments in `js2-scanned-comments'.")
+
+(js2-deflocal js2-scanned-comments nil
+  "List of all comments from the current parse.")
+
+(defcustom js2-mode-indent-inhibit-undo nil
+  "Non-nil to disable collection of Undo information when indenting lines.
+Some users have requested this behavior.  It's nil by default because
+other Emacs modes don't work this way."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-mode-indent-ignore-first-tab nil
+  "If non-nil, ignore first TAB keypress if we look indented properly.
+It's fairly common for users to navigate to an already-indented line
+and press TAB for reassurance that it's been indented.  For this class
+of users, we want the first TAB press on a line to be ignored if the
+line is already indented to one of the precomputed alternatives.
+
+This behavior is only partly implemented.  If you TAB-indent a line,
+navigate to another line, and then navigate back, it fails to clear
+the last-indented variable, so it thinks you've already hit TAB once,
+and performs the indent.  A full solution would involve getting on the
+point-motion hooks for the entire buffer.  If we come across another
+use cases that requires watching point motion, I'll consider doing it.
+
+If you set this variable to nil, then the TAB key will always change
+the indentation of the current line, if more than one alternative
+indentation spot exists."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defvar js2-indent-hook nil
+  "A hook for user-defined indentation rules.
+
+Functions on this hook should expect two arguments:    (LIST INDEX)
+The LIST argument is the list of computed indentation points for
+the current line.  INDEX is the list index of the indentation point
+that `js2-bounce-indent' plans to use.  If INDEX is nil, then the
+indent function is not going to change the current line indentation.
+
+If a hook function on this list returns a non-nil value, then
+`js2-bounce-indent' assumes the hook function has performed its own
+indentation, and will do nothing.  If all hook functions on the list
+return nil, then `js2-bounce-indent' will use its computed indentation
+and reindent the line.
+
+When hook functions on this hook list are called, the variable
+`js2-mode-ast' may or may not be set, depending on whether the
+parse tree is available.  If the variable is nil, you can pass a
+callback to `js2-mode-wait-for-parse', and your callback will be
+called after the new parse tree is built.  This can take some time
+in large files.")
+
+(defface js2-warning-face
+  `((((class color) (background light))
+     (:underline  "orange"))
+    (((class color) (background dark))
+     (:underline "orange"))
+    (t (:underline t)))
+  "Face for JavaScript warnings."
+  :group 'js2-mode)
+
+(defface js2-error-face
+  `((((class color) (background light))
+     (:foreground "red"))
+    (((class color) (background dark))
+     (:foreground "red"))
+    (t (:foreground "red")))
+  "Face for JavaScript errors."
+  :group 'js2-mode)
+
+(defface js2-jsdoc-tag-face
+  '((t :foreground "SlateGray"))
+  "Face used to highlight @whatever tags in jsdoc comments."
+  :group 'js2-mode)
+
+(defface js2-jsdoc-type-face
+  '((t :foreground "SteelBlue"))
+  "Face used to highlight {FooBar} types in jsdoc comments."
+  :group 'js2-mode)
+
+(defface js2-jsdoc-value-face
+  '((t :foreground "PeachPuff3"))
+  "Face used to highlight tag values in jsdoc comments."
+  :group 'js2-mode)
+
+(defface js2-function-param-face
+  '((t :foreground "SeaGreen"))
+  "Face used to highlight function parameters in javascript."
+  :group 'js2-mode)
+
+(defface js2-instance-member-face
+  '((t :foreground "DarkOrchid"))
+  "Face used to highlight instance variables in javascript.
+Not currently used."
+  :group 'js2-mode)
+
+(defface js2-private-member-face
+  '((t :foreground "PeachPuff3"))
+  "Face used to highlight calls to private methods in javascript.
+Not currently used."
+  :group 'js2-mode)
+
+(defface js2-private-function-call-face
+  '((t :foreground "goldenrod"))
+  "Face used to highlight calls to private functions in javascript.
+Not currently used."
+  :group 'js2-mode)
+
+(defface js2-jsdoc-html-tag-name-face
+  (if js2-emacs22
+      '((((class color) (min-colors 88) (background light))
+         (:foreground "rosybrown"))
+        (((class color) (min-colors 8) (background dark))
+         (:foreground "yellow"))
+        (((class color) (min-colors 8) (background light))
+         (:foreground "magenta")))
+    '((((type tty pc) (class color) (background light))
+       (:foreground "magenta"))
+      (((type tty pc) (class color) (background dark))
+       (:foreground "yellow"))
+      (t (:foreground "RosyBrown"))))
+    "Face used to highlight jsdoc html tag names"
+  :group 'js2-mode)
+
+(defface js2-jsdoc-html-tag-delimiter-face
+  (if js2-emacs22
+      '((((class color) (min-colors 88) (background light))
+         (:foreground "dark khaki"))
+        (((class color) (min-colors 8) (background dark))
+         (:foreground "green"))
+        (((class color) (min-colors 8) (background light))
+         (:foreground "green")))
+    '((((type tty pc) (class color) (background light))
+       (:foreground "green"))
+      (((type tty pc) (class color) (background dark))
+       (:foreground "green"))
+      (t (:foreground "dark khaki"))))
+  "Face used to highlight brackets in jsdoc html tags."
+  :group 'js2-mode)
+
+(defface js2-magic-paren-face
+  '((t :underline t))
+  "Face used to color parens that will be auto-overwritten."
+  :group 'js2-mode)
+
+(defcustom js2-post-parse-callbacks nil
+  "A list of callback functions invoked after parsing finishes.
+Currently, the main use for this function is to add synthetic
+declarations to `js2-recorded-assignments', which see."
+  :type 'list
+  :group 'js2-mode)
+
+(defface js2-external-variable-face
+  '((t :foreground "orange"))
+  "Face used to highlight assignments to undeclared variables.
+An undeclared variable is any variable not declared with var or let
+in the current scope or any lexically enclosing scope.  If you assign
+to such a variable, then you are either expecting it to originate from
+another file, or you've got a potential bug."
+  :group 'js2-mode)
+
+(defcustom js2-highlight-external-variables t
+  "Non-nil to higlight assignments to undeclared variables."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defcustom js2-auto-insert-catch-block t
+  "Non-nil to insert matching catch block on open-curly after `try'."
+  :type 'boolean
+  :group 'js2-mode)
+
+(defvar js2-mode-map
+  (let ((map (make-sparse-keymap))
+        keys)
+    (define-key map [mouse-1] #'js2-mode-show-node)
+    (define-key map (kbd "C-m") #'js2-enter-key)
+    (when js2-rebind-eol-bol-keys
+      (define-key map (kbd "C-a") #'js2-beginning-of-line)
+      (define-key map (kbd "C-e") #'js2-end-of-line))
+    (define-key map (kbd "C-c C-e") #'js2-mode-hide-element)
+    (define-key map (kbd "C-c C-s") #'js2-mode-show-element)
+    (define-key map (kbd "C-c C-a") #'js2-mode-show-all)
+    (define-key map (kbd "C-c C-f") #'js2-mode-toggle-hide-functions)
+    (define-key map (kbd "C-c C-t") #'js2-mode-toggle-hide-comments)
+    (define-key map (kbd "C-c C-o") #'js2-mode-toggle-element)
+    (define-key map (kbd "C-c C-w") #'js2-mode-toggle-warnings-and-errors)
+    (define-key map (kbd "C-c C-`") #'js2-next-error)
+    ;; also define user's preference for next-error, if available
+    (if (setq keys (where-is-internal #'next-error))
+        (define-key map (car keys) #'js2-next-error))
+    (define-key map (or (car (where-is-internal #'mark-defun))
+                        (kbd "M-C-h"))
+      #'js2-mark-defun)
+    (define-key map (or (car (where-is-internal #'narrow-to-defun))
+                        (kbd "C-x nd"))
+      #'js2-narrow-to-defun)
+    (define-key map [down-mouse-3] #'js2-down-mouse-3)
+    (when js2-auto-indent-p
+      (mapc (lambda (key)
+              (define-key map key #'js2-insert-and-indent))
+            js2-electric-keys))
+
+    (define-key map [menu-bar javascript]
+      (cons "JavaScript" (make-sparse-keymap "JavaScript")))
+
+    (define-key map [menu-bar javascript customize-js2-mode]
+      '(menu-item "Customize js2-mode" js2-mode-customize
+                  :help "Customize the behavior of this mode"))
+
+    (define-key map [menu-bar javascript js2-force-refresh]
+      '(menu-item "Force buffer refresh" js2-mode-reset
+                  :help "Re-parse the buffer from scratch"))
+
+    (define-key map [menu-bar javascript separator-2]
+      '("--"))
+
+    (define-key map [menu-bar javascript next-error]
+      '(menu-item "Next warning or error" js2-next-error
+                  :enabled (and js2-mode-ast
+                                (or (js2-ast-root-errors js2-mode-ast)
+                                    (js2-ast-root-warnings js2-mode-ast)))
+                  :help "Move to next warning or error"))
+
+    (define-key map [menu-bar javascript display-errors]
+      '(menu-item "Show errors and warnings" 
js2-mode-display-warnings-and-errors
+                  :visible (not js2-mode-show-parse-errors)
+                  :help "Turn on display of warnings and errors"))
+
+    (define-key map [menu-bar javascript hide-errors]
+      '(menu-item "Hide errors and warnings" js2-mode-hide-warnings-and-errors
+                  :visible js2-mode-show-parse-errors
+                  :help "Turn off display of warnings and errors"))
+
+    (define-key map [menu-bar javascript separator-1]
+      '("--"))
+
+    (define-key map [menu-bar javascript js2-toggle-function]
+      '(menu-item "Show/collapse element" js2-mode-toggle-element
+                  :help "Hide or show function body or comment"))
+
+    (define-key map [menu-bar javascript show-comments]
+      '(menu-item "Show block comments" js2-mode-toggle-hide-comments
+                  :visible js2-mode-comments-hidden
+                  :help "Expand all hidden block comments"))
+
+    (define-key map [menu-bar javascript hide-comments]
+      '(menu-item "Hide block comments" js2-mode-toggle-hide-comments
+                  :visible (not js2-mode-comments-hidden)
+                  :help "Show block comments as /*...*/"))
+
+    (define-key map [menu-bar javascript show-all-functions]
+      '(menu-item "Show function bodies" js2-mode-toggle-hide-functions
+                  :visible js2-mode-functions-hidden
+                  :help "Expand all hidden function bodies"))
+
+    (define-key map [menu-bar javascript hide-all-functions]
+      '(menu-item "Hide function bodies" js2-mode-toggle-hide-functions
+                  :visible (not js2-mode-functions-hidden)
+                  :help "Show {...} for all top-level function bodies"))
+
+    map)
+  "Keymap used in `js2-mode' buffers.")
+
+(defconst js2-mode-identifier-re "[a-zA-Z_$][a-zA-Z0-9_$]*")
+
+(defvar js2-mode-//-comment-re "^\\(\\s-*\\)//.+"
+  "Matches a //-comment line.  Must be first non-whitespace on line.
+First match-group is the leading whitespace.")
+
+(defvar js2-mode-hook nil)
+
+(js2-deflocal js2-mode-ast nil "Private variable.")
+(js2-deflocal js2-mode-parse-timer nil "Private variable.")
+(js2-deflocal js2-mode-buffer-dirty-p nil "Private variable.")
+(js2-deflocal js2-mode-parsing nil "Private variable.")
+(js2-deflocal js2-mode-node-overlay nil)
+
+(defvar js2-mode-show-overlay js2-mode-dev-mode-p
+  "Debug:  Non-nil to highlight AST nodes on mouse-down.")
+
+(js2-deflocal js2-mode-fontifications nil "Private variable")
+(js2-deflocal js2-mode-deferred-properties nil "Private variable")
+(js2-deflocal js2-imenu-recorder nil "Private variable")
+(js2-deflocal js2-imenu-function-map nil "Private variable")
+
+(defvar js2-paragraph-start
+  "\\(@[a-zA-Z]+\\>\\|$\\)")
+
+;; Note that we also set a 'c-in-sws text property in html comments,
+;; so that `c-forward-sws' and `c-backward-sws' work properly.
+(defvar js2-syntactic-ws-start
+  "\\s \\|/[*/]\\|[\n\r]\\|\\\\[\n\r]\\|\\s!\\|<!--\\|^\\s-*-->")
+
+(defvar js2-syntactic-ws-end
+  "\\s \\|[\n\r/]\\|\\s!")
+
+(defvar js2-syntactic-eol
+  (concat "\\s *\\(/\\*[^*\n\r]*"
+          "\\(\\*+[^*\n\r/][^*\n\r]*\\)*"
+          "\\*+/\\s *\\)*"
+          "\\(//\\|/\\*[^*\n\r]*"
+          "\\(\\*+[^*\n\r/][^*\n\r]*\\)*$"
+          "\\|\\\\$\\|$\\)")
+  "Copied from `java-mode'.  Needed for some cc-engine functions.")
+
+(defvar js2-comment-prefix-regexp
+  "//+\\|\\**")
+
+(defvar js2-comment-start-skip
+  "\\(//+\\|/\\*+\\)\\s *")
+
+(defvar js2-mode-verbose-parse-p js2-mode-dev-mode-p
+  "Non-nil to emit status messages during parsing.")
+
+(defvar js2-mode-functions-hidden nil "private variable")
+(defvar js2-mode-comments-hidden nil "private variable")
+
+(defvar js2-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    (c-populate-syntax-table table)
+    table)
+  "Syntax table used in js2-mode buffers.")
+
+(defvar js2-mode-abbrev-table nil
+  "Abbrev table in use in `js2-mode' buffers.")
+(define-abbrev-table 'js2-mode-abbrev-table ())
+
+(defvar js2-mode-pending-parse-callbacks nil
+  "List of functions waiting to be notified that parse is finished.")
+
+(defvar js2-mode-last-indented-line -1)
+
+;;; Localizable error and warning messages
+
+;; Messages are copied from Rhino's Messages.properties.
+;; Many of the Java-specific messages have been elided.
+;; Add any js2-specific ones at the end, so we can keep
+;; this file synced with changes to Rhino's.
+
+(defvar js2-message-table
+  (make-hash-table :test 'equal :size 250)
+  "Contains localized messages for js2-mode.")
+
+;; TODO(stevey):  construct this table at compile-time.
+(defmacro js2-msg (key &rest strings)
+  `(puthash ,key (funcall #'concat ,@strings)
+            js2-message-table))
+
+(defun js2-get-msg (msg-key)
+  "Look up a localized message.
+MSG-KEY is a list of (MSG ARGS).  If the message takes parameters,
+the correct number of ARGS must be provided."
+  (let* ((key (if (listp msg-key) (car msg-key) msg-key))
+         (args (if (listp msg-key) (cdr msg-key)))
+         (msg (gethash key js2-message-table)))
+    (if msg
+        (apply #'format msg args)
+      key)))  ; default to showing the key
+
+(js2-msg "msg.dup.parms"
+         "Duplicate parameter name '%s'.")
+
+(js2-msg "msg.too.big.jump"
+         "Program too complex: jump offset too big.")
+
+(js2-msg "msg.too.big.index"
+         "Program too complex: internal index exceeds 64K limit.")
+
+(js2-msg "msg.while.compiling.fn"
+         "Encountered code generation error while compiling function '%s': %s")
+
+(js2-msg "msg.while.compiling.script"
+         "Encountered code generation error while compiling script: %s")
+
+;; Context
+(js2-msg "msg.ctor.not.found"
+         "Constructor for '%s' not found.")
+
+(js2-msg "msg.not.ctor"
+         "'%s' is not a constructor.")
+
+;; FunctionObject
+(js2-msg "msg.varargs.ctor"
+         "Method or constructor '%s' must be static "
+         "with the signature (Context cx, Object[] args, "
+         "Function ctorObj, boolean inNewExpr) "
+         "to define a variable arguments constructor.")
+
+(js2-msg "msg.varargs.fun"
+         "Method '%s' must be static with the signature "
+         "(Context cx, Scriptable thisObj, Object[] args, Function funObj) "
+         "to define a variable arguments function.")
+
+(js2-msg "msg.incompat.call"
+         "Method '%s' called on incompatible object.")
+
+(js2-msg "msg.bad.parms"
+         "Unsupported parameter type '%s' in method '%s'.")
+
+(js2-msg "msg.bad.method.return"
+         "Unsupported return type '%s' in method '%s'.")
+
+(js2-msg "msg.bad.ctor.return"
+         "Construction of objects of type '%s' is not supported.")
+
+(js2-msg "msg.no.overload"
+         "Method '%s' occurs multiple times in class '%s'.")
+
+(js2-msg "msg.method.not.found"
+         "Method '%s' not found in '%s'.")
+
+;; IRFactory
+
+(js2-msg "msg.bad.for.in.lhs"
+         "Invalid left-hand side of for..in loop.")
+
+(js2-msg "msg.mult.index"
+         "Only one variable allowed in for..in loop.")
+
+(js2-msg "msg.bad.for.in.destruct"
+         "Left hand side of for..in loop must be an array of "
+         "length 2 to accept key/value pair.")
+
+(js2-msg "msg.cant.convert"
+         "Can't convert to type '%s'.")
+
+(js2-msg "msg.bad.assign.left"
+         "Invalid assignment left-hand side.")
+
+(js2-msg "msg.bad.decr"
+         "Invalid decerement operand.")
+
+(js2-msg "msg.bad.incr"
+         "Invalid increment operand.")
+
+(js2-msg "msg.bad.yield"
+         "yield must be in a function.")
+
+(js2-msg "msg.yield.parenthesized"
+         "yield expression must be parenthesized.")
+
+;; NativeGlobal
+(js2-msg "msg.cant.call.indirect"
+          "Function '%s' must be called directly, and not by way of a "
+          "function of another name.")
+
+(js2-msg "msg.eval.nonstring"
+          "Calling eval() with anything other than a primitive "
+          "string value will simply return the value. "
+          "Is this what you intended?")
+
+(js2-msg "msg.eval.nonstring.strict"
+         "Calling eval() with anything other than a primitive "
+         "string value is not allowed in strict mode.")
+
+(js2-msg "msg.bad.destruct.op"
+         "Invalid destructuring assignment operator")
+
+;; NativeCall
+(js2-msg "msg.only.from.new"
+         "'%s' may only be invoked from a `new' expression.")
+
+(js2-msg "msg.deprec.ctor"
+         "The '%s' constructor is deprecated.")
+
+;; NativeFunction
+(js2-msg "msg.no.function.ref.found"
+         "no source found to decompile function reference %s")
+
+(js2-msg "msg.arg.isnt.array"
+         "second argument to Function.prototype.apply must be an array")
+
+;; NativeGlobal
+(js2-msg "msg.bad.esc.mask"
+         "invalid string escape mask")
+
+;; NativeRegExp
+(js2-msg "msg.bad.quant"
+  "Invalid quantifier %s")
+
+(js2-msg "msg.overlarge.backref"
+  "Overly large back reference %s")
+
+(js2-msg "msg.overlarge.min"
+  "Overly large minimum %s")
+
+(js2-msg "msg.overlarge.max"
+  "Overly large maximum %s")
+
+(js2-msg "msg.zero.quant"
+  "Zero quantifier %s")
+
+(js2-msg "msg.max.lt.min"
+  "Maximum %s less than minimum")
+
+(js2-msg "msg.unterm.quant"
+  "Unterminated quantifier %s")
+
+(js2-msg "msg.unterm.paren"
+  "Unterminated parenthetical %s")
+
+(js2-msg "msg.unterm.class"
+  "Unterminated character class %s")
+
+(js2-msg "msg.bad.range"
+  "Invalid range in character class.")
+
+(js2-msg "msg.trail.backslash"
+  "Trailing \\ in regular expression.")
+
+(js2-msg "msg.re.unmatched.right.paren"
+  "unmatched ) in regular expression.")
+
+(js2-msg "msg.no.regexp"
+  "Regular expressions are not available.")
+
+(js2-msg "msg.bad.backref"
+  "back-reference exceeds number of capturing parentheses.")
+
+(js2-msg "msg.bad.regexp.compile"
+         "Only one argument may be specified if the first "
+         "argument to RegExp.prototype.compile is a RegExp object.")
+
+;; Parser
+(js2-msg "msg.got.syntax.errors"
+         "Compilation produced %s syntax errors.")
+
+(js2-msg "msg.var.redecl"
+         "TypeError: redeclaration of var %s.")
+
+(js2-msg "msg.const.redecl"
+         "TypeError: redeclaration of const %s.")
+
+(js2-msg "msg.let.redecl"
+         "TypeError: redeclaration of variable %s.")
+
+(js2-msg "msg.parm.redecl"
+         "TypeError: redeclaration of formal parameter %s.")
+
+(js2-msg "msg.fn.redecl"
+         "TypeError: redeclaration of function %s.")
+
+(js2-msg "msg.let.decl.not.in.block"
+         "SyntaxError: let declaration not directly within block")
+
+;; NodeTransformer
+(js2-msg "msg.dup.label"
+         "duplicated label")
+
+(js2-msg "msg.undef.label"
+         "undefined label")
+
+(js2-msg "msg.bad.break"
+         "unlabelled break must be inside loop or switch")
+
+(js2-msg "msg.continue.outside"
+         "continue must be inside loop")
+
+(js2-msg "msg.continue.nonloop"
+         "continue can only use labels of iteration statements")
+
+(js2-msg "msg.bad.throw.eol"
+         "Line terminator is not allowed between the throw "
+         "keyword and throw expression.")
+
+(js2-msg "msg.no.paren.parms"
+         "missing ( before function parameters.")
+
+(js2-msg "msg.no.parm"
+         "missing formal parameter")
+
+(js2-msg "msg.no.paren.after.parms"
+         "missing ) after formal parameters")
+
+(js2-msg "msg.no.brace.body"
+         "missing '{' before function body")
+
+(js2-msg "msg.no.brace.after.body"
+         "missing } after function body")
+
+(js2-msg "msg.no.paren.cond"
+         "missing ( before condition")
+
+(js2-msg "msg.no.paren.after.cond"
+         "missing ) after condition")
+
+(js2-msg "msg.no.semi.stmt"
+         "missing ; before statement")
+
+(js2-msg "msg.missing.semi"
+         "missing ; after statement")
+
+(js2-msg "msg.no.name.after.dot"
+         "missing name after . operator")
+
+(js2-msg "msg.no.name.after.coloncolon"
+         "missing name after :: operator")
+
+(js2-msg "msg.no.name.after.dotdot"
+         "missing name after .. operator")
+
+(js2-msg "msg.no.name.after.xmlAttr"
+         "missing name after .@")
+
+(js2-msg "msg.no.bracket.index"
+         "missing ] in index expression")
+
+(js2-msg "msg.no.paren.switch"
+         "missing ( before switch expression")
+
+(js2-msg "msg.no.paren.after.switch"
+         "missing ) after switch expression")
+
+(js2-msg "msg.no.brace.switch"
+         "missing '{' before switch body")
+
+(js2-msg "msg.bad.switch"
+         "invalid switch statement")
+
+(js2-msg "msg.no.colon.case"
+         "missing : after case expression")
+
+(js2-msg "msg.double.switch.default"
+         "double default label in the switch statement")
+
+(js2-msg "msg.no.while.do"
+         "missing while after do-loop body")
+
+(js2-msg "msg.no.paren.for"
+         "missing ( after for")
+
+(js2-msg "msg.no.semi.for"
+         "missing ; after for-loop initializer")
+
+(js2-msg "msg.no.semi.for.cond"
+         "missing ; after for-loop condition")
+
+(js2-msg "msg.in.after.for.name"
+         "missing in after for")
+
+(js2-msg "msg.no.paren.for.ctrl"
+         "missing ) after for-loop control")
+
+(js2-msg "msg.no.paren.with"
+         "missing ( before with-statement object")
+
+(js2-msg "msg.no.paren.after.with"
+         "missing ) after with-statement object")
+
+(js2-msg "msg.no.paren.after.let"
+         "missing ( after let")
+
+(js2-msg "msg.no.paren.let"
+         "missing ) after variable list")
+
+(js2-msg "msg.no.curly.let"
+         "missing } after let statement")
+
+(js2-msg "msg.bad.return"
+         "invalid return")
+
+(js2-msg "msg.no.brace.block"
+         "missing } in compound statement")
+
+(js2-msg "msg.bad.label"
+         "invalid label")
+
+(js2-msg "msg.bad.var"
+         "missing variable name")
+
+(js2-msg "msg.bad.var.init"
+         "invalid variable initialization")
+
+(js2-msg "msg.no.colon.cond"
+         "missing : in conditional expression")
+
+(js2-msg "msg.no.paren.arg"
+         "missing ) after argument list")
+
+(js2-msg "msg.no.bracket.arg"
+         "missing ] after element list")
+
+(js2-msg "msg.bad.prop"
+         "invalid property id")
+
+(js2-msg "msg.no.colon.prop"
+         "missing : after property id")
+
+(js2-msg "msg.no.brace.prop"
+         "missing } after property list")
+
+(js2-msg "msg.no.paren"
+         "missing ) in parenthetical")
+
+(js2-msg "msg.reserved.id"
+         "identifier is a reserved word")
+
+(js2-msg "msg.no.paren.catch"
+         "missing ( before catch-block condition")
+
+(js2-msg "msg.bad.catchcond"
+         "invalid catch block condition")
+
+(js2-msg "msg.catch.unreachable"
+         "any catch clauses following an unqualified catch are unreachable")
+
+(js2-msg "msg.no.brace.try"
+         "missing '{' before try block")
+
+(js2-msg "msg.no.brace.catchblock"
+         "missing '{' before catch-block body")
+
+(js2-msg "msg.try.no.catchfinally"
+         "'try' without 'catch' or 'finally'")
+
+(js2-msg "msg.no.return.value"
+         "function %s does not always return a value")
+
+(js2-msg "msg.anon.no.return.value"
+         "anonymous function does not always return a value")
+
+(js2-msg "msg.return.inconsistent"
+         "return statement is inconsistent with previous usage")
+
+(js2-msg "msg.generator.returns"
+         "TypeError: generator function '%s' returns a value")
+
+(js2-msg "msg.anon.generator.returns"
+         "TypeError: anonymous generator function returns a value")
+
+(js2-msg "msg.syntax"
+         "syntax error")
+
+(js2-msg "msg.unexpected.eof"
+         "Unexpected end of file")
+
+(js2-msg "msg.XML.bad.form"
+         "illegally formed XML syntax")
+
+(js2-msg "msg.XML.not.available"
+         "XML runtime not available")
+
+(js2-msg "msg.too.deep.parser.recursion"
+         "Too deep recursion while parsing")
+
+(js2-msg "msg.no.side.effects"
+         "Code has no side effects")
+
+(js2-msg "msg.extra.trailing.comma"
+         "Trailing comma is not legal in an ECMA-262 object initializer")
+
+(js2-msg "msg.array.trailing.comma"
+         "Trailing comma yields different behavior across browsers")
+
+(js2-msg "msg.equal.as.assign"
+         (concat "Test for equality (==) mistyped as assignment (=)?"
+                 " (parenthesize to suppress warning)"))
+
+(js2-msg "msg.var.hides.arg"
+         "Variable %s hides argument")
+
+(js2-msg "msg.destruct.assign.no.init"
+         "Missing = in destructuring declaration")
+
+;; ScriptRuntime
+(js2-msg "msg.no.properties"
+         "%s has no properties.")
+
+(js2-msg "msg.invalid.iterator"
+         "Invalid iterator value")
+
+(js2-msg "msg.iterator.primitive"
+         "__iterator__ returned a primitive value")
+
+(js2-msg "msg.assn.create.strict"
+         "Assignment to undeclared variable %s")
+
+(js2-msg "msg.ref.undefined.prop"
+         "Reference to undefined property '%s'")
+
+(js2-msg "msg.prop.not.found"
+         "Property %s not found.")
+
+(js2-msg "msg.invalid.type"
+         "Invalid JavaScript value of type %s")
+
+(js2-msg "msg.primitive.expected"
+         "Primitive type expected (had %s instead)")
+
+(js2-msg "msg.namespace.expected"
+         "Namespace object expected to left of :: (found %s instead)")
+
+(js2-msg "msg.null.to.object"
+         "Cannot convert null to an object.")
+
+(js2-msg "msg.undef.to.object"
+         "Cannot convert undefined to an object.")
+
+(js2-msg "msg.cyclic.value"
+         "Cyclic %s value not allowed.")
+
+(js2-msg "msg.is.not.defined"
+         "'%s' is not defined.")
+
+(js2-msg "msg.undef.prop.read"
+         "Cannot read property '%s' from %s")
+
+(js2-msg "msg.undef.prop.write"
+         "Cannot set property '%s' of %s to '%s'")
+
+(js2-msg "msg.undef.prop.delete"
+         "Cannot delete property '%s' of %s")
+
+(js2-msg "msg.undef.method.call"
+         "Cannot call method '%s' of %s")
+
+(js2-msg "msg.undef.with"
+         "Cannot apply 'with' to %s")
+
+(js2-msg "msg.isnt.function"
+         "%s is not a function, it is %s.")
+
+(js2-msg "msg.isnt.function.in"
+         "Cannot call property %s in object %s. "
+         "It is not a function, it is '%s'.")
+
+(js2-msg "msg.function.not.found"
+         "Cannot find function %s.")
+
+(js2-msg "msg.function.not.found.in"
+         "Cannot find function %s in object %s.")
+
+(js2-msg "msg.isnt.xml.object"
+         "%s is not an xml object.")
+
+(js2-msg "msg.no.ref.to.get"
+         "%s is not a reference to read reference value.")
+
+(js2-msg "msg.no.ref.to.set"
+         "%s is not a reference to set reference value to %s.")
+
+(js2-msg "msg.no.ref.from.function"
+         "Function %s can not be used as the left-hand "
+         "side of assignment or as an operand of ++ or -- operator.")
+
+(js2-msg "msg.bad.default.value"
+         "Object's getDefaultValue() method returned an object.")
+
+(js2-msg "msg.instanceof.not.object"
+         "Can't use instanceof on a non-object.")
+
+(js2-msg "msg.instanceof.bad.prototype"
+         "'prototype' property of %s is not an object.")
+
+(js2-msg "msg.bad.radix"
+         "illegal radix %s.")
+
+;; ScriptableObject
+(js2-msg "msg.default.value"
+         "Cannot find default value for object.")
+
+(js2-msg "msg.zero.arg.ctor"
+         "Cannot load class '%s' which has no zero-parameter constructor.")
+
+(js2-msg "msg.ctor.multiple.parms"
+         "Can't define constructor or class %s since more than "
+         "one constructor has multiple parameters.")
+
+(js2-msg "msg.extend.scriptable"
+         "%s must extend ScriptableObject in order to define property %s.")
+
+(js2-msg "msg.bad.getter.parms"
+         "In order to define a property, getter %s must have zero "
+         "parameters or a single ScriptableObject parameter.")
+
+(js2-msg "msg.obj.getter.parms"
+         "Expected static or delegated getter %s to take "
+         "a ScriptableObject parameter.")
+
+(js2-msg "msg.getter.static"
+         "Getter and setter must both be static or neither be static.")
+
+(js2-msg "msg.setter.return"
+         "Setter must have void return type: %s")
+
+(js2-msg "msg.setter2.parms"
+         "Two-parameter setter must take a ScriptableObject as "
+         "its first parameter.")
+
+(js2-msg "msg.setter1.parms"
+         "Expected single parameter setter for %s")
+
+(js2-msg "msg.setter2.expected"
+         "Expected static or delegated setter %s to take two parameters.")
+
+(js2-msg "msg.setter.parms"
+         "Expected either one or two parameters for setter.")
+
+(js2-msg "msg.setter.bad.type"
+         "Unsupported parameter type '%s' in setter '%s'.")
+
+(js2-msg "msg.add.sealed"
+         "Cannot add a property to a sealed object: %s.")
+
+(js2-msg "msg.remove.sealed"
+         "Cannot remove a property from a sealed object: %s.")
+
+(js2-msg "msg.modify.sealed"
+         "Cannot modify a property of a sealed object: %s.")
+
+(js2-msg "msg.modify.readonly"
+         "Cannot modify readonly property: %s.")
+
+;; TokenStream
+(js2-msg "msg.missing.exponent"
+         "missing exponent")
+
+(js2-msg "msg.caught.nfe"
+         "number format error")
+
+(js2-msg "msg.unterminated.string.lit"
+         "unterminated string literal")
+
+(js2-msg "msg.unterminated.comment"
+         "unterminated comment")
+
+(js2-msg "msg.unterminated.re.lit"
+         "unterminated regular expression literal")
+
+(js2-msg "msg.invalid.re.flag"
+         "invalid flag after regular expression")
+
+(js2-msg "msg.no.re.input.for"
+         "no input for %s")
+
+(js2-msg "msg.illegal.character"
+         "illegal character")
+
+(js2-msg "msg.invalid.escape"
+         "invalid Unicode escape sequence")
+
+(js2-msg "msg.bad.namespace"
+         "not a valid default namespace statement. "
+         "Syntax is: default xml namespace = EXPRESSION;")
+
+;; TokensStream warnings
+(js2-msg "msg.bad.octal.literal"
+         "illegal octal literal digit %s; "
+         "interpreting it as a decimal digit")
+
+(js2-msg "msg.reserved.keyword"
+         "illegal usage of future reserved keyword %s; "
+         "interpreting it as ordinary identifier")
+
+(js2-msg "msg.script.is.not.constructor"
+         "Script objects are not constructors.")
+
+;; Arrays
+(js2-msg "msg.arraylength.bad"
+         "Inappropriate array length.")
+
+;; Arrays
+(js2-msg "msg.arraylength.too.big"
+         "Array length %s exceeds supported capacity limit.")
+
+;; URI
+(js2-msg "msg.bad.uri"
+         "Malformed URI sequence.")
+
+;; Number
+(js2-msg "msg.bad.precision"
+         "Precision %s out of range.")
+
+;; NativeGenerator
+(js2-msg "msg.send.newborn"
+         "Attempt to send value to newborn generator")
+
+(js2-msg "msg.already.exec.gen"
+         "Already executing generator")
+
+(js2-msg "msg.StopIteration.invalid"
+         "StopIteration may not be changed to an arbitrary object.")
+
+;; Interpreter
+(js2-msg "msg.yield.closing"
+         "Yield from closing generator")
+
+;;; Utilities
+
+(defun js2-delete-if (predicate list)
+  "Remove all items satisfying PREDICATE in LIST."
+  (loop for item in list
+        if (not (funcall predicate item))
+        collect item))
+
+(defun js2-position (element list)
+  "Find 0-indexed position of ELEMENT in LIST comparing with `eq'.
+Returns nil if element is not found in the list."
+  (let ((count 0)
+        found)
+    (while (and list (not found))
+      (if (eq element (car list))
+          (setq found t)
+        (setq count (1+ count)
+              list (cdr list))))
+    (if found count)))
+
+(defun js2-find-if (predicate list)
+  "Find first item satisfying PREDICATE in LIST."
+  (let (result)
+    (while (and list (not result))
+      (if (funcall predicate (car list))
+          (setq result (car list)))
+      (setq list (cdr list)))
+    result))
+
+(defmacro js2-time (form)
+  "Evaluate FORM, discard result, and return elapsed time in sec"
+  (declare (debug t))
+  (let ((beg (make-symbol "--js2-time-beg--"))
+        (delta (make-symbol "--js2-time-end--")))
+    `(let ((,beg (current-time))
+           ,delta)
+       ,form
+       (/ (truncate (* (- (float-time (current-time))
+                          (float-time ,beg)))
+                    10000)
+          10000.0))))
+
+(defsubst js2-same-line (pos)
+  "Return t if POS is on the same line as current point."
+  (and (>= pos (point-at-bol))
+       (<= pos (point-at-eol))))
+
+(defsubst js2-same-line-2 (p1 p2)
+  "Return t if p1 is on the same line as p2."
+  (save-excursion
+    (goto-char p1)
+    (js2-same-line p2)))
+
+(defun js2-code-bug ()
+  "Signal an error when we encounter an unexpected code path."
+  (error "failed assertion"))
+
+;; I'd like to associate errors with nodes, but for now the
+;; easiest thing to do is get the context info from the last token.
+(defsubst js2-record-parse-error (msg &optional arg pos len)
+  (push (list (list msg arg)
+              (or pos js2-token-beg)
+              (or len (- js2-token-end js2-token-beg)))
+        js2-parsed-errors))
+
+(defsubst js2-report-error (msg &optional msg-arg pos len)
+  "Signal a syntax error or record a parse error."
+  (if js2-recover-from-parse-errors
+      (js2-record-parse-error msg msg-arg pos len)
+  (signal 'js2-syntax-error
+          (list msg
+                js2-ts-lineno
+                (save-excursion
+                  (goto-char js2-ts-cursor)
+                  (current-column))
+                js2-ts-hit-eof))))
+
+(defsubst js2-report-warning (msg &optional msg-arg pos len)
+  (if js2-compiler-report-warning-as-error
+      (js2-report-error msg msg-arg pos len)
+    (push (list (list msg msg-arg)
+                (or pos js2-token-beg)
+                (or len (- js2-token-end js2-token-beg)))
+          js2-parsed-warnings)))
+
+(defsubst js2-add-strict-warning (msg-id &optional msg-arg beg end)
+  (if js2-compiler-strict-mode
+      (js2-report-warning msg-id msg-arg beg
+                          (and beg end (- end beg)))))
+
+(put 'js2-syntax-error 'error-conditions
+     '(error syntax-error js2-syntax-error))
+(put 'js2-syntax-error 'error-message "Syntax error")
+
+(put 'js2-parse-error 'error-conditions
+     '(error parse-error js2-parse-error))
+(put 'js2-parse-error 'error-message "Parse error")
+
+(defmacro js2-clear-flag (flags flag)
+  `(setq ,flags (logand ,flags (lognot ,flag))))
+
+(defmacro js2-set-flag (flags flag)
+  "Logical-or FLAG into FLAGS."
+  `(setq ,flags (logior ,flags ,flag)))
+
+(defsubst js2-flag-set-p (flags flag)
+  (/= 0 (logand flags flag)))
+
+(defsubst js2-flag-not-set-p (flags flag)
+  (zerop (logand flags flag)))
+
+;; Stolen shamelessly from James Clark's nxml-mode.
+(defmacro js2-with-unmodifying-text-property-changes (&rest body)
+  "Evaluate BODY without any text property changes modifying the buffer.
+Any text properties changes happen as usual but the changes are not treated as
+modifications to the buffer."
+  (declare (indent 0) (debug t))
+  (let ((modified (make-symbol "modified")))
+    `(let ((,modified (buffer-modified-p))
+          (inhibit-read-only t)
+          (inhibit-modification-hooks t)
+          (buffer-undo-list t)
+          (deactivate-mark nil)
+          ;; Apparently these avoid file locking problems.
+          (buffer-file-name nil)
+          (buffer-file-truename nil))
+       (unwind-protect
+          (progn ,@body)
+        (unless ,modified
+          (restore-buffer-modified-p nil))))))
+
+(defmacro js2-with-underscore-as-word-syntax (&rest body)
+  "Evaluate BODY with the _ character set to be word-syntax."
+  (declare (indent 0) (debug t))
+  (let ((old-syntax (make-symbol "old-syntax")))
+  `(let ((,old-syntax (string (char-syntax ?_))))
+     (unwind-protect
+         (progn
+           (modify-syntax-entry ?_ "w" js2-mode-syntax-table)
+           ,@body)
+       (modify-syntax-entry ?_ ,old-syntax js2-mode-syntax-table)))))
+
+(defsubst js2-char-uppercase-p (c)
+  "Return t if C is an uppercase character.
+Handles unicode and latin chars properly."
+  (/= c (downcase c)))
+
+(defsubst js2-char-lowercase-p (c)
+  "Return t if C is an uppercase character.
+Handles unicode and latin chars properly."
+  (/= c (upcase c)))
+
+;;; AST struct and function definitions
+
+;; flags for ast node property 'member-type (used for e4x operators)
+(defvar js2-property-flag    #x1 "property access: element is valid name")
+(defvar js2-attribute-flag   #x2 "address@hidden or address@hidden")
+(defvar js2-descendants-flag #x4 "x..y or address@hidden")
+
+(defsubst js2-relpos (pos anchor)
+  "Convert POS to be relative to ANCHOR.
+If POS is nil, returns nil."
+  (and pos (- pos anchor)))
+
+(defsubst js2-make-pad (indent)
+  (if (zerop indent)
+      ""
+    (make-string (* indent js2-basic-offset) ? )))
+
+(defsubst js2-visit-ast (node callback)
+  "Visit every node in ast NODE with visitor CALLBACK.
+
+CALLBACK is a function that takes two arguments:  (NODE END-P).  It is
+called twice:  once to visit the node, and again after all the node's
+children have been processed.  The END-P argument is nil on the first
+call and non-nil on the second call.  The return value of the callback
+affects the traversal:  if non-nil, the children of NODE are processed.
+If the callback returns nil, or if the node has no children, then the
+callback is called immediately with a non-nil END-P argument.
+
+The node traversal is approximately lexical-order, although there
+are currently no guarantees around this."
+  (let ((vfunc (get (aref node 0) 'js2-visitor)))
+    ;; visit the node
+    (when  (funcall callback node nil)
+      ;; visit the kids
+      (cond
+       ((eq vfunc 'js2-visit-none)
+        nil)                            ; don't even bother calling it
+       ;; Each AST node type has to define a `js2-visitor' function
+       ;; that takes a node and a callback, and calls `js2-visit-ast'
+       ;; on each child of the node.
+       (vfunc
+        (funcall vfunc node callback))
+       (t
+        (error "%s does not define a visitor-traversal function"
+               (aref node 0)))))
+    ;; call the end-visit
+    (funcall callback node t)))
+
+(defstruct (js2-node
+            (:constructor nil))  ; abstract
+  "Base AST node type."
+  (type -1)  ; token type
+  (pos -1)   ; start position of this AST node in parsed input
+  (len 1)    ; num characters spanned by the node
+  props      ; optional node property list (an alist)
+  parent)    ; link to parent node; null for root
+
+(defsubst js2-node-get-prop (node prop &optional default)
+  (or (cadr (assoc prop (js2-node-props node))) default))
+
+(defsubst js2-node-set-prop (node prop value)
+  (setf (js2-node-props node)
+        (cons (list prop value) (js2-node-props node))))
+
+(defsubst js2-fixup-starts (n nodes)
+  "Adjust the start positions of NODES to be relative to N.
+Any node in the list may be nil, for convenience."
+  (dolist (node nodes)
+    (when node
+      (setf (js2-node-pos node) (- (js2-node-pos node)
+                                   (js2-node-pos n))))))
+
+(defsubst js2-node-add-children (parent &rest nodes)
+  "Set parent node of NODES to PARENT, and return PARENT.
+Does nothing if we're not recording parent links.
+If any given node in NODES is nil, doesn't record that link."
+  (js2-fixup-starts parent nodes)
+  (dolist (node nodes)
+    (and node
+         (setf (js2-node-parent node) parent))))
+
+;; Non-recursive since it's called a frightening number of times.
+(defsubst js2-node-abs-pos (n)
+  (let ((pos (js2-node-pos n)))
+    (while (setq n (js2-node-parent n))
+      (setq pos (+ pos (js2-node-pos n))))
+    pos))
+
+(defsubst js2-node-abs-end (n)
+  "Return absolute buffer position of end of N."
+  (+ (js2-node-abs-pos n) (js2-node-len n)))
+
+;; It's important to make sure block nodes have a lisp list for the
+;; child nodes, to limit printing recursion depth in an AST that
+;; otherwise consists of defstruct vectors.  Emacs will crash printing
+;; a sufficiently large vector tree.
+
+(defstruct (js2-block-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-block-node (&key (type js2-BLOCK)
+                                                    (pos js2-token-beg)
+                                                    len
+                                                    props
+                                                    kids)))
+  "A block of statements."
+  kids)  ; a lisp list of the child statement nodes
+
+(put 'cl-struct-js2-block-node 'js2-visitor 'js2-visit-block)
+(put 'cl-struct-js2-block-node 'js2-printer 'js2-print-block)
+
+(defsubst js2-visit-block (ast callback)
+  "Visit the `js2-block-node' children of AST."
+  (dolist (kid (js2-block-node-kids ast))
+    (js2-visit-ast kid callback)))
+
+(defun js2-print-block (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad "{\n")
+    (dolist (kid (js2-block-node-kids n))
+      (js2-print-ast kid (1+ i)))
+    (insert pad "}")))
+
+(defstruct (js2-scope
+            (:include js2-block-node)
+            (:constructor nil)
+            (:constructor make-js2-scope (&key (type js2-BLOCK)
+                                               (pos js2-token-beg)
+                                               len
+                                               kids)))
+  ;; The symbol-table is a LinkedHashMap<String,Symbol> in Rhino.
+  ;; I don't have one of those handy, so I'll use an alist for now.
+  ;; It's as fast as an emacs hashtable for up to about 50 elements,
+  ;; and is much lighter-weight to construct (both CPU and mem).
+  ;; The keys are interned strings (symbols) for faster lookup.
+  ;; Should switch to hybrid alist/hashtable eventually.
+  symbol-table  ; an alist of (symbol . js2-symbol)
+  parent-scope  ; a `js2-scope'
+  top)          ; top-level `js2-scope' (script/function)
+
+(put 'cl-struct-js2-scope 'js2-visitor 'js2-visit-block)
+(put 'cl-struct-js2-scope 'js2-printer 'js2-print-none)
+
+(defun js2-scope-set-parent-scope (scope parent)
+  (setf (js2-scope-parent-scope scope) parent
+        (js2-scope-top scope) (if (null parent)
+                                  scope
+                                (js2-scope-top parent))))
+
+(defun js2-node-get-enclosing-scope (node)
+  "Return the innermost `js2-scope' node surrounding NODE.
+Returns nil if there is no enclosing scope node."
+  (let ((parent (js2-node-parent node)))
+    (while (not (js2-scope-p parent))
+      (setq parent (js2-node-parent parent)))
+    parent))
+
+(defun js2-get-defining-scope (scope name)
+  "Search up scope chain from SCOPE looking for NAME, a string or symbol.
+Returns `js2-scope' in which NAME is defined, or nil if not found."
+  (let ((sym (if (symbolp name)
+                 name
+               (intern name)))
+        table
+        result
+        (continue t))
+    (while (and scope continue)
+      (if (and (setq table (js2-scope-symbol-table scope))
+               (assq sym table))
+          (setq continue nil
+                result scope)
+        (setq scope (js2-scope-parent-scope scope))))
+    result))
+
+(defsubst js2-scope-get-symbol (scope name)
+  "Return symbol table entry for NAME in SCOPE.
+NAME can be a string or symbol.   Returns a `js2-symbol' or nil if not found."
+  (and (js2-scope-symbol-table scope)
+       (cdr (assq (if (symbolp name)
+                      name
+                    (intern name))
+                  (js2-scope-symbol-table scope)))))
+
+(defsubst js2-scope-put-symbol (scope name symbol)
+  "Enter SYMBOL into symbol-table for SCOPE under NAME.
+NAME can be a lisp symbol or string.  SYMBOL is a `js2-symbol'."
+  (let* ((table (js2-scope-symbol-table scope))
+         (sym (if (symbolp name) name (intern name)))
+         (entry (assq sym table)))
+    (if entry
+        (setcdr entry symbol)
+      (push (cons sym symbol)
+            (js2-scope-symbol-table scope)))))
+
+(defstruct (js2-symbol
+            (:constructor nil)
+            (:constructor make-js2-symbol (decl-type name &optional ast-node)))
+  "A symbol table entry."
+  ;; One of js2-FUNCTION, js2-LP (for parameters), js2-VAR,
+  ;; js2-LET, or js2-CONST
+  decl-type
+  name  ; string
+  ast-node) ; a `js2-node'
+
+(defstruct (js2-error-node
+            (:include js2-node)
+            (:constructor nil) ; silence emacs21 byte-compiler
+            (:constructor make-js2-error-node (&key (type js2-ERROR)
+                                                    (pos js2-token-beg)
+                                                    len)))
+  "AST node representing a parse error.")
+
+(put 'cl-struct-js2-error-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-error-node 'js2-printer 'js2-print-none)
+
+(defstruct (js2-script-node
+            (:include js2-scope)
+            (:constructor nil)
+            (:constructor make-js2-script-node (&key (type js2-SCRIPT)
+                                                     (pos js2-token-beg)
+                                                     len
+                                                     var-decls
+                                                     fun-decls)))
+  functions   ; lisp list of nested functions
+  regexps     ; lisp list of (string . flags)
+  symbols     ; alist (every symbol gets unique index)
+  (param-count 0)
+  var-names   ; vector of string names
+  consts      ; bool-vector matching var-decls
+  (temp-number 0))  ; for generating temp variables
+
+(put 'cl-struct-js2-script-node 'js2-visitor 'js2-visit-block)
+(put 'cl-struct-js2-script-node 'js2-printer 'js2-print-script)
+
+(defun js2-print-script (node indent)
+  (dolist (kid (js2-block-node-kids node))
+    (js2-print-ast kid indent)))
+
+(defstruct (js2-ast-root
+            (:include js2-script-node)
+            (:constructor nil)
+            (:constructor make-js2-ast-root (&key (type js2-SCRIPT)
+                                                  (pos js2-token-beg)
+                                                  len
+                                                  buffer)))
+  "The root node of a js2 AST."
+  buffer         ; the source buffer from which the code was parsed
+  comments       ; a lisp list of comments, ordered by start position
+  errors         ; a lisp list of errors found during parsing
+  warnings       ; a lisp list of warnings found during parsing
+  node-count)    ; number of nodes in the tree, including the root
+
+(put 'cl-struct-js2-ast-root 'js2-visitor 'js2-visit-ast-root)
+(put 'cl-struct-js2-ast-root 'js2-printer 'js2-print-script)
+
+(defun js2-visit-ast-root (ast callback)
+  (dolist (kid (js2-ast-root-kids ast))
+    (js2-visit-ast kid callback))
+  (dolist (comment (js2-ast-root-comments ast))
+    (js2-visit-ast comment callback)))
+
+(defstruct (js2-comment-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-comment-node (&key (type js2-COMMENT)
+                                                      (pos js2-token-beg)
+                                                      len
+                                                      (format 
js2-ts-comment-type))))
+  format)  ; 'line, 'block, 'jsdoc or 'html
+
+(put 'cl-struct-js2-comment-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-comment-node 'js2-printer 'js2-print-comment)
+
+(defun js2-print-comment (n i)
+  ;; We really ought to link end-of-line comments to their nodes.
+  ;; Or maybe we could add a new comment type, 'endline.
+  (insert (js2-make-pad i)
+          (js2-node-string n)))
+
+(defstruct (js2-expr-stmt-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-expr-stmt-node (&key (type js2-EXPR_VOID)
+                                                        (pos js2-ts-cursor)
+                                                        len
+                                                        expr)))
+  "An expression statement."
+  expr)
+
+(defsubst js2-expr-stmt-node-set-has-result (node)
+  "Change the node type to `js2-EXPR_RESULT'.  Used for code generation."
+  (setf (js2-node-type node) js2-EXPR_RESULT))
+
+(put 'cl-struct-js2-expr-stmt-node 'js2-visitor 'js2-visit-expr-stmt-node)
+(put 'cl-struct-js2-expr-stmt-node 'js2-printer 'js2-print-expr-stmt-node)
+
+(defun js2-visit-expr-stmt-node (n v)
+  (js2-visit-ast (js2-expr-stmt-node-expr n) v))
+
+(defun js2-print-expr-stmt-node (n indent)
+  (js2-print-ast (js2-expr-stmt-node-expr n) indent)
+  (insert ";\n"))
+
+(defstruct (js2-loop-node
+            (:include js2-scope)
+            (:constructor nil))
+  "Abstract supertype of loop nodes."
+  body      ; a `js2-block-node'
+  lp        ; position of left-paren, nil if omitted
+  rp)       ; position of right-paren, nil if omitted
+
+(defstruct (js2-do-node
+            (:include js2-loop-node)
+            (:constructor nil)
+            (:constructor make-js2-do-node (&key (type js2-DO)
+                                                 (pos js2-token-beg)
+                                                 len
+                                                 body
+                                                 condition
+                                                 while-pos
+                                                 lp
+                                                 rp)))
+  "AST node for do-loop."
+  condition  ; while (expression)
+  while-pos) ; buffer position of 'while' keyword
+
+(put 'cl-struct-js2-do-node 'js2-visitor 'js2-visit-do-node)
+(put 'cl-struct-js2-do-node 'js2-printer 'js2-print-do-node)
+
+(defun js2-visit-do-node (n v)
+  (js2-visit-ast (js2-do-node-body n) v)
+  (js2-visit-ast (js2-do-node-condition n) v))
+
+(defun js2-print-do-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad "do {\n")
+    (dolist (kid (js2-block-node-kids (js2-do-node-body n)))
+      (js2-print-ast kid (1+ i)))
+    (insert pad "} while (")
+    (js2-print-ast (js2-do-node-condition n) 0)
+    (insert ");\n")))
+
+(defstruct (js2-while-node
+            (:include js2-loop-node)
+            (:constructor nil)
+            (:constructor make-js2-while-node (&key (type js2-WHILE)
+                                                    (pos js2-token-beg)
+                                                    len
+                                                    body
+                                                    condition
+                                                    lp
+                                                    rp)))
+  "AST node for while-loop."
+  condition)    ; while-condition
+
+(put 'cl-struct-js2-while-node 'js2-visitor 'js2-visit-while-node)
+(put 'cl-struct-js2-while-node 'js2-printer 'js2-print-while-node)
+
+(defun js2-visit-while-node (n v)
+  (js2-visit-ast (js2-while-node-condition n) v)
+  (js2-visit-ast (js2-while-node-body n) v))
+
+(defun js2-print-while-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad "while (")
+    (js2-print-ast (js2-while-node-condition n) 0)
+    (insert ") {\n")
+    (js2-print-body (js2-while-node-body n) (1+ i))
+    (insert pad "}\n")))
+
+(defstruct (js2-for-node
+            (:include js2-loop-node)
+            (:constructor nil)
+            (:constructor make-js2-for-node (&key (type js2-FOR)
+                                                  (pos js2-ts-cursor)
+                                                  len
+                                                  body
+                                                  init
+                                                  condition
+                                                  update
+                                                  lp
+                                                  rp)))
+  "AST node for a C-style for-loop."
+  init       ; initialization expression
+  condition  ; loop condition
+  update)    ; update clause
+
+(put 'cl-struct-js2-for-node 'js2-visitor 'js2-visit-for-node)
+(put 'cl-struct-js2-for-node 'js2-printer 'js2-print-for-node)
+
+(defun js2-visit-for-node (n v)
+  (js2-visit-ast (js2-for-node-init n) v)
+  (js2-visit-ast (js2-for-node-condition n) v)
+  (js2-visit-ast (js2-for-node-update n) v)
+  (js2-visit-ast (js2-for-node-body n) v))
+
+(defun js2-print-for-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad "for (")
+    (js2-print-ast (js2-for-node-init n) 0)
+    (insert "; ")
+    (js2-print-ast (js2-for-node-condition n) 0)
+    (insert "; ")
+    (js2-print-ast (js2-for-node-update n) 0)
+    (insert ") {\n")
+    (js2-print-body (js2-for-node-body n) (1+ i))
+    (insert pad "}\n")))
+
+(defstruct (js2-for-in-node
+            (:include js2-loop-node)
+            (:constructor nil)
+            (:constructor make-js2-for-in-node (&key (type js2-FOR)
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     body
+                                                     iterator
+                                                     object
+                                                     in-pos
+                                                     each-pos
+                                                     foreach-p
+                                                     lp
+                                                     rp)))
+  "AST node for a for..in loop."
+  iterator  ; [var] foo in ...
+  object    ; object over which we're iterating
+  in-pos    ; buffer position of 'in' keyword
+  each-pos  ; buffer position of 'each' keyword, if foreach-p
+  foreach-p) ; t if it's a for-each loop
+
+(put 'cl-struct-js2-for-in-node 'js2-visitor 'js2-visit-for-in-node)
+(put 'cl-struct-js2-for-in-node 'js2-printer 'js2-print-for-in-node)
+
+(defun js2-visit-for-in-node (n v)
+  (js2-visit-ast (js2-for-in-node-iterator n) v)
+  (js2-visit-ast (js2-for-in-node-object n) v)
+  (js2-visit-ast (js2-for-in-node-body n) v))
+
+(defun js2-print-for-in-node (n i)
+  (let ((pad (js2-make-pad i))
+        (foreach (js2-for-in-node-foreach-p n)))
+    (insert pad "for ")
+    (if foreach
+        (insert "each "))
+    (insert "(")
+    (js2-print-ast (js2-for-in-node-iterator n) 0)
+    (insert " in ")
+    (js2-print-ast (js2-for-in-node-object n) 0)
+    (insert ") {\n")
+    (js2-print-body (js2-for-in-node-body n) (1+ i))
+    (insert pad "}\n")))
+
+(defstruct (js2-return-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-return-node (&key (type js2-RETURN)
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     retval)))
+  "AST node for a return statement."
+  retval)  ; expression to return, or 'undefined
+
+(put 'cl-struct-js2-return-node 'js2-visitor 'js2-visit-return-node)
+(put 'cl-struct-js2-return-node 'js2-printer 'js2-print-return-node)
+
+(defun js2-visit-return-node (n v)
+  (if (js2-return-node-retval n)
+      (js2-visit-ast (js2-return-node-retval n) v)))
+
+(defun js2-print-return-node (n i)
+  (insert (js2-make-pad i) "return")
+  (when (js2-return-node-retval n)
+    (insert " ")
+    (js2-print-ast (js2-return-node-retval n) 0))
+  (insert ";\n"))
+
+(defstruct (js2-if-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-if-node (&key (type js2-IF)
+                                                 (pos js2-ts-cursor)
+                                                 len
+                                                 condition
+                                                 then-part
+                                                 else-pos
+                                                 else-part
+                                                 lp
+                                                 rp)))
+  "AST node for an if-statement."
+  condition   ; expression
+  then-part   ; statement or block
+  else-pos    ; optional buffer position of 'else' keyword
+  else-part   ; optional statement or block
+  lp          ; position of left-paren, nil if omitted
+  rp)         ; position of right-paren, nil if omitted
+
+(put 'cl-struct-js2-if-node 'js2-visitor 'js2-visit-if-node)
+(put 'cl-struct-js2-if-node 'js2-printer 'js2-print-if-node)
+
+(defun js2-visit-if-node (n v)
+  (js2-visit-ast (js2-if-node-condition n) v)
+  (js2-visit-ast (js2-if-node-then-part n) v)
+  (if (js2-if-node-else-part n)
+      (js2-visit-ast (js2-if-node-else-part n) v)))
+
+(defun js2-print-if-node (n i)
+  (let ((pad (js2-make-pad i))
+        (then-part (js2-if-node-then-part n))
+        (else-part (js2-if-node-else-part n)))
+    (insert pad "if (")
+    (js2-print-ast (js2-if-node-condition n) 0)
+    (insert ") {\n")
+    (js2-print-body then-part (1+ i))
+    (insert pad "}")
+    (cond
+     ((not else-part)
+      (insert "\n"))
+     ((js2-if-node-p else-part)
+      (insert " else ")
+      (js2-print-body else-part i))
+     (t
+      (insert " else {\n")
+      (js2-print-body else-part (1+ i))
+      (insert pad "}\n")))))
+
+(defstruct (js2-try-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-try-node (&key (type js2-TRY)
+                                                  (pos js2-ts-cursor)
+                                                  len
+                                                  try-block
+                                                  catch-clauses
+                                                  finally-block)))
+  "AST node for a try-statement."
+  try-block
+  catch-clauses  ; a lisp list of `js2-catch-node'
+  finally-block) ; a `js2-finally-node'
+
+(put 'cl-struct-js2-try-node 'js2-visitor 'js2-visit-try-node)
+(put 'cl-struct-js2-try-node 'js2-printer 'js2-print-try-node)
+
+(defun js2-visit-try-node (n v)
+  (js2-visit-ast (js2-try-node-try-block n) v)
+  (dolist (clause (js2-try-node-catch-clauses n))
+    (js2-visit-ast clause v))
+  (if (js2-try-node-finally-block n)
+      (js2-visit-ast (js2-try-node-finally-block n) v)))
+
+(defun js2-print-try-node (n i)
+  (let ((pad (js2-make-pad i))
+        (catches (js2-try-node-catch-clauses n))
+        (finally (js2-try-node-finally-block n)))
+    (insert pad "try {\n")
+    (js2-print-body (js2-try-node-try-block n) (1+ i))
+    (insert pad "}")
+    (when catches
+      (dolist (catch catches)
+        (js2-print-ast catch i)))
+    (if finally
+        (js2-print-ast finally i)
+      (insert "\n"))))
+
+(defstruct (js2-catch-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-catch-node (&key (type js2-CATCH)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    var-name
+                                                    guard-kwd
+                                                    guard-expr
+                                                    block
+                                                    lp
+                                                    rp)))
+  "AST node for a catch clause."
+  var-name    ; a `js2-name-node'
+  guard-kwd   ; relative buffer position of "if" in "catch (x if ...)"
+  guard-expr  ; catch condition, a `js2-node'
+  block       ; statements, a `js2-block-node'
+  lp          ; buffer position of left-paren, nil if omitted
+  rp)         ; buffer position of right-paren, nil if omitted
+
+(put 'cl-struct-js2-catch-node 'js2-visitor 'js2-visit-catch-node)
+(put 'cl-struct-js2-catch-node 'js2-printer 'js2-print-catch-node)
+
+(defun js2-visit-catch-node (n v)
+  (js2-visit-ast (js2-catch-node-var-name n) v)
+  (when (js2-catch-node-guard-kwd n)
+    (js2-visit-ast (js2-catch-node-guard-expr n) v))
+  (js2-visit-ast (js2-catch-node-block n) v))
+
+(defun js2-print-catch-node (n i)
+  (let ((pad (js2-make-pad i))
+        (guard-kwd (js2-catch-node-guard-kwd n))
+        (guard-expr (js2-catch-node-guard-expr n)))
+    (insert " catch (")
+    (js2-print-ast (js2-catch-node-var-name n) 0)
+    (when guard-kwd
+      (insert " if ")
+      (js2-print-ast guard-expr 0))
+    (insert ") {\n")
+    (js2-print-body (js2-catch-node-block n) (1+ i))
+    (insert pad "}")))
+
+(defstruct (js2-finally-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-finally-node (&key (type js2-FINALLY)
+                                                      (pos js2-ts-cursor)
+                                                      len
+                                                      body)))
+  "AST node for a finally clause."
+  body)  ; a `js2-node', often but not always a block node
+
+(put 'cl-struct-js2-finally-node 'js2-visitor 'js2-visit-finally-node)
+(put 'cl-struct-js2-finally-node 'js2-printer 'js2-print-finally-node)
+
+(defun js2-visit-finally-node (n v)
+  (js2-visit-ast (js2-finally-node-body n) v))
+
+(defun js2-print-finally-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert " finally {\n")
+    (js2-print-body (js2-finally-node-body n) (1+ i))
+    (insert pad "}\n")))
+
+(defstruct (js2-switch-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-switch-node (&key (type js2-SWITCH)
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     discriminant
+                                                     cases
+                                                     lp
+                                                     rp)))
+  "AST node for a switch statement."
+  discriminant  ; a `js2-node' (switch expression)
+  cases  ; a lisp list of `js2-case-node'
+  lp     ; position of open-paren for discriminant, nil if omitted
+  rp)    ; position of close-paren for discriminant, nil if omitted
+
+(put 'cl-struct-js2-switch-node 'js2-visitor 'js2-visit-switch-node)
+(put 'cl-struct-js2-switch-node 'js2-printer 'js2-print-switch-node)
+
+(defun js2-visit-switch-node (n v)
+  (js2-visit-ast (js2-switch-node-discriminant n) v)
+  (dolist (c (js2-switch-node-cases n))
+    (js2-visit-ast c v)))
+
+(defun js2-print-switch-node (n i)
+  (let ((pad (js2-make-pad i))
+        (cases (js2-switch-node-cases n)))
+    (insert pad "switch (")
+    (js2-print-ast (js2-switch-node-discriminant n) 0)
+    (insert ") {\n")
+    (dolist (case cases)
+      (js2-print-ast case i))
+    (insert pad "}\n")))
+
+(defstruct (js2-case-node
+            (:include js2-block-node)
+            (:constructor nil)
+            (:constructor make-js2-case-node (&key (type js2-CASE)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   kids
+                                                   expr)))
+  "AST node for a case clause of a switch statement."
+  expr)   ; the case expression (nil for default)
+
+(put 'cl-struct-js2-case-node 'js2-visitor 'js2-visit-case-node)
+(put 'cl-struct-js2-case-node 'js2-printer 'js2-print-case-node)
+
+(defun js2-visit-case-node (n v)
+  (if (js2-case-node-expr n)  ; nil for default: case
+      (js2-visit-ast (js2-case-node-expr n) v))
+  (js2-visit-block n v))
+
+(defun js2-print-case-node (n i)
+  (let ((pad (js2-make-pad i))
+        (expr (js2-case-node-expr n)))
+    (insert pad)
+    (if (null expr)
+        (insert "default:\n")
+      (insert "case ")
+      (js2-print-ast expr 0)
+      (insert ":\n"))
+    (dolist (kid (js2-case-node-kids n))
+      (js2-print-ast kid (1+ i)))))
+
+(defstruct (js2-throw-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-throw-node (&key (type js2-THROW)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    expr)))
+  "AST node for a throw statement."
+  expr)   ; the expression to throw
+
+(put 'cl-struct-js2-throw-node 'js2-visitor 'js2-visit-throw-node)
+(put 'cl-struct-js2-throw-node 'js2-printer 'js2-print-throw-node)
+
+(defun js2-visit-throw-node (n v)
+  (js2-visit-ast (js2-throw-node-expr n) v))
+
+(defun js2-print-throw-node (n i)
+  (insert (js2-make-pad i) "throw ")
+  (js2-print-ast (js2-throw-node-expr n) 0)
+  (insert ";\n"))
+
+(defstruct (js2-with-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-with-node (&key (type js2-WITH)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   object
+                                                   body
+                                                   lp
+                                                   rp)))
+  "AST node for a with-statement."
+  object
+  body
+  lp    ; buffer position of left-paren around object, nil if omitted
+  rp)   ; buffer position of right-paren around object, nil if omitted
+
+(put 'cl-struct-js2-with-node 'js2-visitor 'js2-visit-with-node)
+(put 'cl-struct-js2-with-node 'js2-printer 'js2-print-with-node)
+
+(defun js2-visit-with-node (n v)
+  (js2-visit-ast (js2-with-node-object n) v)
+  (js2-visit-ast (js2-with-node-body n) v))
+
+(defun js2-print-with-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad "with (")
+    (js2-print-ast (js2-with-node-object n) 0)
+    (insert ") {\n")
+    (js2-print-body (js2-with-node-body n) (1+ i))
+    (insert pad "}\n")))
+
+(defstruct (js2-label-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-label-node (&key (type js2-LABEL)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    name)))
+  "AST node for a statement label or case label."
+  name   ; a string
+  loop)  ; for validating and code-generating continue-to-label
+
+(put 'cl-struct-js2-label-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-label-node 'js2-printer 'js2-print-label)
+
+(defun js2-print-label (n i)
+  (insert (js2-make-pad i)
+          (js2-label-node-name n)
+          ":\n"))
+
+(defstruct (js2-labeled-stmt-node
+            (:include js2-node)
+            (:constructor nil)
+            ;; type needs to be in `js2-side-effecting-tokens' to avoid 
spurious
+            ;; no-side-effects warnings, hence js2-EXPR_RESULT.
+            (:constructor make-js2-labeled-stmt-node (&key (type 
js2-EXPR_RESULT)
+                                                           (pos js2-ts-cursor)
+                                                           len
+                                                           labels
+                                                           stmt)))
+  "AST node for a statement with one or more labels.
+Multiple labels for a statement are collapsed into the labels field."
+  labels  ; lisp list of `js2-label-node'
+  stmt)   ; the statement these labels are for
+
+(put 'cl-struct-js2-labeled-stmt-node 'js2-visitor 'js2-visit-labeled-stmt)
+(put 'cl-struct-js2-labeled-stmt-node 'js2-printer 'js2-print-labeled-stmt)
+
+(defun js2-get-label-by-name (lbl-stmt name)
+  "Return a `js2-label-node' by NAME from LBL-STMT's labels list.
+Returns nil if no such label is in the list."
+  (let ((label-list (js2-labeled-stmt-node-labels lbl-stmt))
+        result)
+    (while (and label-list (not result))
+      (if (string= (js2-label-node-name (car label-list)) name)
+          (setq result (car label-list))
+        (setq label-list (cdr label-list))))
+    result))
+
+(defun js2-visit-labeled-stmt (n v)
+  (dolist (label (js2-labeled-stmt-node-labels n))
+    (js2-visit-ast label v))
+  (js2-visit-ast (js2-labeled-stmt-node-stmt n) v))
+
+(defun js2-print-labeled-stmt (n i)
+  (dolist (label (js2-labeled-stmt-node-labels n))
+    (js2-print-ast label i))
+  (js2-print-ast (js2-labeled-stmt-node-stmt n) (1+ i)))
+
+(defun js2-labeled-stmt-node-contains (node label)
+  "Return t if NODE contains LABEL in its label set.
+NODE is a `js2-labels-node'.  LABEL is an identifier."
+  (loop for nl in (js2-labeled-stmt-node-labels node)
+        if (string= label (js2-label-node-name nl))
+          return t
+        finally return nil))
+
+(defsubst js2-labeled-stmt-node-add-label (node label)
+  "Add a `js2-label-node' to the label set for this statement."
+  (setf (js2-labeled-stmt-node-labels node)
+        (nconc (js2-labeled-stmt-node-labels node) (list label))))
+
+(defstruct (js2-jump-node
+            (:include js2-node)
+            (:constructor nil))
+  "Abstract supertype of break and continue nodes."
+  label   ; `js2-name-node' for location of label identifier, if present
+  target) ; target js2-labels-node or loop/switch statement
+
+(defun js2-visit-jump-node (n v)
+  ;; we don't visit the target, since it's a back-link
+  (if (js2-jump-node-label n)
+      (js2-visit-ast (js2-jump-node-label n) v)))
+
+(defstruct (js2-break-node
+            (:include js2-jump-node)
+            (:constructor nil)
+            (:constructor make-js2-break-node (&key (type js2-BREAK)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    label
+                                                    target)))
+  "AST node for a break statement.
+The label field is a `js2-name-node', possibly nil, for the named label
+if provided.  E.g. in 'break foo', it represents 'foo'.  The target field
+is the target of the break - a label node or enclosing loop/switch statement.")
+
+(put 'cl-struct-js2-break-node 'js2-visitor 'js2-visit-jump-node)
+(put 'cl-struct-js2-break-node 'js2-printer 'js2-print-break-node)
+
+(defun js2-print-break-node (n i)
+  (insert (js2-make-pad i) "break")
+  (when (js2-break-node-label n)
+    (insert " ")
+    (js2-print-ast (js2-break-node-label n) 0))
+  (insert ";\n"))
+
+(defstruct (js2-continue-node
+            (:include js2-jump-node)
+            (:constructor nil)
+            (:constructor make-js2-continue-node (&key (type js2-CONTINUE)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       label
+                                                       target)))
+  "AST node for a continue statement.
+The label field is the user-supplied enclosing label name, a `js2-name-node'.
+It is nil if continue specifies no label.  The target field is the jump target:
+a `js2-label-node' or the innermost enclosing loop.")
+
+(put 'cl-struct-js2-continue-node 'js2-visitor 'js2-visit-jump-node)
+(put 'cl-struct-js2-continue-node 'js2-printer 'js2-print-continue-node)
+
+(defun js2-print-continue-node (n i)
+  (insert (js2-make-pad i) "continue")
+  (when (js2-continue-node-label n)
+    (insert " ")
+    (js2-print-ast (js2-continue-node-label n) 0))
+  (insert ";\n"))
+
+(defstruct (js2-function-node
+            (:include js2-script-node)
+            (:constructor nil)
+            (:constructor make-js2-function-node (&key (type js2-FUNCTION)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       (ftype 'FUNCTION)
+                                                       (form 
'FUNCTION_STATEMENT)
+                                                       (name "")
+                                                       params
+                                                       body
+                                                       lp
+                                                       rp)))
+  "AST node for a function declaration.
+The `params' field is a lisp list of nodes.  Each node is either a simple
+`js2-name-node', or if it's a destructuring-assignment parameter, a
+`js2-array-node' or `js2-object-node'."
+  ftype            ; FUNCTION, GETTER or SETTER
+  form             ; FUNCTION_{STATEMENT|EXPRESSION|EXPRESSION_STATEMENT}
+  name             ; function name (a `js2-name-node', or nil if anonymous)
+  params           ; a lisp list of destructuring forms or simple name nodes
+  body             ; a `js2-block-node' or expression node (1.8 only)
+  lp               ; position of arg-list open-paren, or nil if omitted
+  rp               ; position of arg-list close-paren, or nil if omitted
+  ignore-dynamic   ; ignore value of the dynamic-scope flag (interpreter only)
+  needs-activation ; t if we need an activation object for this frame
+  is-generator     ; t if this function contains a yield
+  member-expr)     ; nonstandard Ecma extension from Rhino
+
+(put 'cl-struct-js2-function-node 'js2-visitor 'js2-visit-function-node)
+(put 'cl-struct-js2-function-node 'js2-printer 'js2-print-function-node)
+
+(defun js2-visit-function-node (n v)
+  (if (js2-function-node-name n)
+      (js2-visit-ast (js2-function-node-name n) v))
+  (dolist (p (js2-function-node-params n))
+    (js2-visit-ast p v))
+  (when (js2-function-node-body n)
+    (js2-visit-ast (js2-function-node-body n) v)))
+
+(defun js2-print-function-node (n i)
+  (let ((pad (js2-make-pad i))
+        (getter (js2-node-get-prop n 'GETTER_SETTER))
+        (name (js2-function-node-name n))
+        (params (js2-function-node-params n))
+        (body (js2-function-node-body n))
+        (expr (eq (js2-function-node-form n) 'FUNCTION_EXPRESSION)))
+    (unless getter
+      (insert pad "function"))
+    (when name
+        (insert " ")
+        (js2-print-ast name 0))
+    (insert "(")
+    (loop with len = (length params)
+          for param in params
+          for count from 1
+          do
+          (js2-print-ast param 0)
+          (if (< count len)
+              (insert ", ")))
+    (insert ") {")
+    (unless expr
+      (insert "\n"))
+    ;; TODO:  fix this to be smarter about indenting, etc.
+    (js2-print-body body (1+ i))
+    (insert pad "}")
+    (unless expr
+      (insert "\n"))))
+
+(defsubst js2-function-name (node)
+  "Return function name for NODE, a `js2-function-node', or nil if anonymous."
+  (and (js2-function-node-name node)
+       (js2-name-node-name (js2-function-node-name node))))
+
+;; Having this be an expression node makes it more flexible.
+;; There are IDE contexts, such as indentation in a for-loop initializer,
+;; that work better if you assume it's an expression.  Whenever we have
+;; a standalone var/const declaration, we just wrap with an expr stmt.
+;; Eclipse apparently screwed this up and now has two versions, expr and stmt.
+(defstruct (js2-var-decl-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-var-decl-node (&key (type js2-VAR)
+                                                       (pos js2-token-beg)
+                                                       len
+                                                       kids
+                                                       decl-type)))
+  "AST node for a variable declaration list (VAR, CONST or LET).
+The node bounds differ depending on the declaration type.  For VAR or
+CONST declarations, the bounds include the var/const keyword.  For LET
+declarations, the node begins at the position of the first child."
+  kids        ; a lisp list of `js2-var-init-node' structs.
+  decl-type)  ; js2-VAR, js2-CONST or js2-LET
+
+(put 'cl-struct-js2-var-decl-node 'js2-visitor 'js2-visit-var-decl)
+(put 'cl-struct-js2-var-decl-node 'js2-printer 'js2-print-var-decl)
+
+(defun js2-visit-var-decl (n v)
+  (dolist (kid (js2-var-decl-node-kids n))
+    (js2-visit-ast kid v)))
+
+(defun js2-print-var-decl (n i)
+  (let ((pad (js2-make-pad i))
+        (tt (js2-var-decl-node-decl-type n)))
+    (insert pad)
+    (insert (cond
+             ((= tt js2-VAR) "var ")
+             ((= tt js2-LET) "")  ; handled by parent let-{expr/stmt}
+             ((= tt js2-CONST) "const ")
+             (t
+              (error "malformed var-decl node"))))
+    (loop with kids = (js2-var-decl-node-kids n)
+          with len = (length kids)
+          for kid in kids
+          for count from 1
+          do
+          (js2-print-ast kid 0)
+          (if (< count len)
+              (insert ", ")))))
+
+(defstruct (js2-var-init-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-var-init-node (&key (type js2-VAR)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       target
+                                                       initializer)))
+  "AST node for a variable declaration.
+The type field will be js2-CONST for a const decl."
+  target        ; `js2-name-node', `js2-object-node', or `js2-array-node'
+  initializer)  ; initializer expression, a `js2-node'
+
+(put 'cl-struct-js2-var-init-node 'js2-visitor 'js2-visit-var-init-node)
+(put 'cl-struct-js2-var-init-node 'js2-printer 'js2-print-var-init-node)
+
+(defun js2-visit-var-init-node (n v)
+  (js2-visit-ast (js2-var-init-node-target n) v)
+  (if (js2-var-init-node-initializer n)
+      (js2-visit-ast (js2-var-init-node-initializer n) v)))
+
+(defun js2-print-var-init-node (n i)
+  (let ((pad (js2-make-pad i))
+        (name (js2-var-init-node-target n))
+        (init (js2-var-init-node-initializer n)))
+    (insert pad)
+    (js2-print-ast name 0)
+    (when init
+      (insert " = ")
+      (js2-print-ast init 0))))
+
+(defstruct (js2-cond-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-cond-node (&key (type js2-HOOK)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   test-expr
+                                                   true-expr
+                                                   false-expr
+                                                   q-pos
+                                                   c-pos)))
+  "AST node for the ternary operator"
+  test-expr
+  true-expr
+  false-expr
+  q-pos   ; buffer position of ?
+  c-pos)  ; buffer position of :
+
+(put 'cl-struct-js2-cond-node 'js2-visitor 'js2-visit-cond-node)
+(put 'cl-struct-js2-cond-node 'js2-printer 'js2-print-cond-node)
+
+(defun js2-visit-cond-node (n v)
+  (js2-visit-ast (js2-cond-node-test-expr n) v)
+  (js2-visit-ast (js2-cond-node-true-expr n) v)
+  (js2-visit-ast (js2-cond-node-false-expr n) v))
+
+(defun js2-print-cond-node (n i)
+  (let ((pad (js2-make-pad i)))
+    (insert pad)
+    (js2-print-ast (js2-cond-node-test-expr n) 0)
+    (insert " ? ")
+    (js2-print-ast (js2-cond-node-true-expr n) 0)
+    (insert " : ")
+    (js2-print-ast (js2-cond-node-false-expr n) 0)))
+
+(defstruct (js2-infix-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-infix-node (&key type
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    op-pos
+                                                    left
+                                                    right)))
+  "Represents infix expressions.
+Includes assignment ops like `|=', and the comma operator.
+The type field inherited from `js2-node' holds the operator."
+  op-pos    ; buffer position where operator begins
+  left      ; any `js2-node'
+  right)    ; any `js2-node'
+
+(put 'cl-struct-js2-infix-node 'js2-visitor 'js2-visit-infix-node)
+(put 'cl-struct-js2-infix-node 'js2-printer 'js2-print-infix-node)
+
+(defun js2-visit-infix-node (n v)
+  (when (js2-infix-node-left n)
+    (js2-visit-ast (js2-infix-node-left n) v))
+  (when (js2-infix-node-right n)
+    (js2-visit-ast (js2-infix-node-right n) v)))
+
+(defconst js2-operator-tokens
+  (let ((table (make-hash-table :test 'eq))
+        (tokens
+         (list (cons js2-IN "in")
+               (cons js2-TYPEOF "typeof")
+               (cons js2-INSTANCEOF "instanceof")
+               (cons js2-DELPROP "delete")
+               (cons js2-COMMA ",")
+               (cons js2-COLON ":")
+               (cons js2-OR "||")
+               (cons js2-AND "&&")
+               (cons js2-INC "++")
+               (cons js2-DEC "--")
+               (cons js2-BITOR "|")
+               (cons js2-BITXOR "^")
+               (cons js2-BITAND "&")
+               (cons js2-EQ "==")
+               (cons js2-NE "!=")
+               (cons js2-LT "<")
+               (cons js2-LE "<=")
+               (cons js2-GT ">")
+               (cons js2-GE ">=")
+               (cons js2-LSH "<<")
+               (cons js2-RSH ">>")
+               (cons js2-URSH ">>>")
+               (cons js2-ADD "+")       ; infix plus
+               (cons js2-SUB "-")       ; infix minus
+               (cons js2-MUL "*")
+               (cons js2-DIV "/")
+               (cons js2-MOD "%")
+               (cons js2-NOT "!")
+               (cons js2-BITNOT "~")
+               (cons js2-POS "+")       ; unary plus
+               (cons js2-NEG "-")       ; unary minus
+               (cons js2-SHEQ "===")    ; shallow equality
+               (cons js2-SHNE "!==")    ; shallow inequality
+               (cons js2-ASSIGN "=")
+               (cons js2-ASSIGN_BITOR "|=")
+               (cons js2-ASSIGN_BITXOR "^=")
+               (cons js2-ASSIGN_BITAND "&=")
+               (cons js2-ASSIGN_LSH "<<=")
+               (cons js2-ASSIGN_RSH ">>=")
+               (cons js2-ASSIGN_URSH ">>>=")
+               (cons js2-ASSIGN_ADD "+=")
+               (cons js2-ASSIGN_SUB "-=")
+               (cons js2-ASSIGN_MUL "*=")
+               (cons js2-ASSIGN_DIV "/=")
+               (cons js2-ASSIGN_MOD "%="))))
+    (loop for (k . v) in tokens do
+          (puthash k v table))
+    table))
+
+(defun js2-print-infix-node (n i)
+  (let* ((tt (js2-node-type n))
+         (op (gethash tt js2-operator-tokens)))
+    (unless op
+      (error "unrecognized infix operator %s" (js2-node-type n)))
+    (insert (js2-make-pad i))
+    (js2-print-ast (js2-infix-node-left n) 0)
+    (unless (= tt js2-COMMA)
+      (insert " "))
+    (insert op)
+    (insert " ")
+    (js2-print-ast (js2-infix-node-right n) 0)))
+
+(defstruct (js2-assign-node
+            (:include js2-infix-node)
+            (:constructor nil)
+            (:constructor make-js2-assign-node (&key type
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     op-pos
+                                                     left
+                                                     right)))
+  "Represents any assignment.
+The type field holds the actual assignment operator.")
+
+(put 'cl-struct-js2-assign-node 'js2-visitor 'js2-visit-infix-node)
+(put 'cl-struct-js2-assign-node 'js2-printer 'js2-print-infix-node)
+
+(defstruct (js2-unary-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-unary-node (&key type ; required
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    operand)))
+  "AST node type for unary operator nodes.
+The type field can be NOT, BITNOT, POS, NEG, INC, DEC,
+TYPEOF, or DELPROP.  For INC or DEC, a 'postfix node
+property is added if the operator follows the operand."
+  operand)  ; a `js2-node' expression
+
+(put 'cl-struct-js2-unary-node 'js2-visitor 'js2-visit-unary-node)
+(put 'cl-struct-js2-unary-node 'js2-printer 'js2-print-unary-node)
+
+(defun js2-visit-unary-node (n v)
+  (js2-visit-ast (js2-unary-node-operand n) v))
+
+(defun js2-print-unary-node (n i)
+  (let* ((tt (js2-node-type n))
+         (op (gethash tt js2-operator-tokens))
+         (postfix (js2-node-get-prop n 'postfix)))
+    (unless op
+      (error "unrecognized unary operator %s" tt))
+    (insert (js2-make-pad i))
+    (unless postfix
+      (insert op))
+    (if (or (= tt js2-TYPEOF)
+            (= tt js2-DELPROP))
+        (insert " "))
+    (js2-print-ast (js2-unary-node-operand n) 0)
+    (when postfix
+      (insert op))))
+
+(defstruct (js2-let-node
+            (:include js2-scope)
+            (:constructor nil)
+            (:constructor make-js2-let-node (&key (type js2-LETEXPR)
+                                                  (pos js2-token-beg)
+                                                  len
+                                                  vars
+                                                  body
+                                                  lp
+                                                  rp)))
+  "AST node for a let expression or a let statement.
+Note that a let declaration such as let x=6, y=7 is a `js2-var-decl-node'."
+  vars   ; a `js2-var-decl-node'
+  body   ; a `js2-node' representing the expression or body block
+  lp
+  rp)
+
+(put 'cl-struct-js2-let-node 'js2-visitor 'js2-visit-let-node)
+(put 'cl-struct-js2-let-node 'js2-printer 'js2-print-let-node)
+
+(defun js2-visit-let-node (n v)
+  (when (js2-let-node-vars n)
+    (js2-visit-ast (js2-let-node-vars n) v))
+  (when (js2-let-node-body n)
+    (js2-visit-ast (js2-let-node-body n) v)))
+
+(defun js2-print-let-node (n i)
+  (insert (js2-make-pad i) "let (")
+  (js2-print-ast (js2-let-node-vars n) 0)
+  (insert ") ")
+  (js2-print-ast (js2-let-node-body n) i))
+
+(defstruct (js2-keyword-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-keyword-node (&key type
+                                                      (pos js2-token-beg)
+                                                      (len (- js2-ts-cursor 
pos)))))
+  "AST node representing a literal keyword such as `null'.
+Used for `null', `this', `true', `false' and `debugger'.
+The node type is set to js2-NULL, js2-THIS, etc.")
+
+(put 'cl-struct-js2-keyword-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-keyword-node 'js2-printer 'js2-print-keyword-node)
+
+(defun js2-print-keyword-node (n i)
+  (insert (js2-make-pad i)
+          (let ((tt (js2-node-type n)))
+            (cond
+             ((= tt js2-THIS) "this")
+             ((= tt js2-NULL) "null")
+             ((= tt js2-TRUE) "true")
+             ((= tt js2-FALSE) "false")
+             ((= tt js2-DEBUGGER) "debugger")
+             (t (error "Invalid keyword literal type: %d" tt))))))
+
+(defsubst js2-this-node-p (node)
+  "Return t if this node is a `js2-literal-node' of type js2-THIS."
+  (eq (js2-node-type node) js2-THIS))
+
+(defstruct (js2-new-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-new-node (&key (type js2-NEW)
+                                                  (pos js2-token-beg)
+                                                  len
+                                                  target
+                                                  args
+                                                  initializer
+                                                  lp
+                                                  rp)))
+  "AST node for new-expression such as new Foo()."
+  target  ; an identifier or reference
+  args    ; a lisp list of argument nodes
+  lp      ; position of left-paren, nil if omitted
+  rp      ; position of right-paren, nil if omitted
+  initializer) ; experimental Rhino syntax:  optional `js2-object-node'
+
+(put 'cl-struct-js2-new-node 'js2-visitor 'js2-visit-new-node)
+(put 'cl-struct-js2-new-node 'js2-printer 'js2-print-new-node)
+
+(defun js2-visit-new-node (n v)
+  (js2-visit-ast (js2-new-node-target n) v)
+  (dolist (arg (js2-new-node-args n))
+    (js2-visit-ast arg v))
+  (when (js2-new-node-initializer n)
+    (js2-visit-ast (js2-new-node-initializer n) v)))
+
+(defun js2-print-new-node (n i)
+  (insert (js2-make-pad i) "new ")
+  (js2-print-ast (js2-new-node-target n))
+  (insert "(")
+  (js2-print-list (js2-new-node-args n))
+  (insert ")")
+  (when (js2-new-node-initializer n)
+    (insert " ")
+    (js2-print-ast (js2-new-node-initializer n))))
+
+(defstruct (js2-name-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-name-node (&key (type js2-NAME)
+                                                   (pos js2-token-beg)
+                                                   (len (- js2-ts-cursor
+                                                           js2-token-beg))
+                                                   (name js2-ts-string))))
+  "AST node for a JavaScript identifier"
+  name   ; a string
+  scope) ; a `js2-scope' (optional, used for codegen)
+
+(put 'cl-struct-js2-name-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-name-node 'js2-printer 'js2-print-name-node)
+
+(defun js2-print-name-node (n i)
+  (insert (js2-make-pad i)
+          (js2-name-node-name n)))
+
+(defsubst js2-name-node-length (node)
+  "Return identifier length of NODE, a `js2-name-node'.
+Returns 0 if NODE is nil or its identifier field is nil."
+  (if node
+      (length (js2-name-node-name node))
+    0))
+
+(defstruct (js2-number-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-number-node (&key (type js2-NUMBER)
+                                                     (pos js2-token-beg)
+                                                     (len (- js2-ts-cursor
+                                                             js2-token-beg))
+                                                     (value js2-ts-string)
+                                                     (num-value 
js2-ts-number))))
+  "AST node for a number literal."
+  value      ; the original string, e.g. "6.02e23"
+  num-value) ; the parsed number value
+
+(put 'cl-struct-js2-number-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-number-node 'js2-printer 'js2-print-number-node)
+
+(defun js2-print-number-node (n i)
+  (insert (js2-make-pad i)
+          (number-to-string (js2-number-node-num-value n))))
+
+(defstruct (js2-regexp-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-regexp-node (&key (type js2-REGEXP)
+                                                     (pos js2-token-beg)
+                                                     (len (- js2-ts-cursor
+                                                             js2-token-beg))
+                                                     value
+                                                     flags)))
+  "AST node for a regular expression literal."
+  value  ; the regexp string, without // delimiters
+  flags) ; a string of flags, e.g. `mi'.
+
+(put 'cl-struct-js2-regexp-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-regexp-node 'js2-printer 'js2-print-regexp)
+
+(defun js2-print-regexp (n i)
+  (insert (js2-make-pad i)
+          "/"
+          (js2-regexp-node-value n)
+          "/")
+  (if (js2-regexp-node-flags n)
+      (insert (js2-regexp-node-flags n))))
+
+(defstruct (js2-string-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-string-node (&key (type js2-STRING)
+                                                     (pos js2-token-beg)
+                                                     (len (- js2-ts-cursor
+                                                             js2-token-beg))
+                                                     (value js2-ts-string))))
+  "String literal.
+Escape characters are not evaluated; e.g. \n is 2 chars in value field.
+You can tell the quote type by looking at the first character."
+  value) ; the characters of the string, including the quotes
+
+(put 'cl-struct-js2-string-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-string-node 'js2-printer 'js2-print-string-node)
+
+(defun js2-print-string-node (n i)
+  (insert (js2-make-pad i)
+          (js2-node-string n)))
+
+(defstruct (js2-array-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-array-node (&key (type js2-ARRAYLIT)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    elems)))
+  "AST node for an array literal."
+  elems)  ; list of expressions.  [foo,,bar] yields a nil middle element.
+
+(put 'cl-struct-js2-array-node 'js2-visitor 'js2-visit-array-node)
+(put 'cl-struct-js2-array-node 'js2-printer 'js2-print-array-node)
+
+(defun js2-visit-array-node (n v)
+  (dolist (e (js2-array-node-elems n))
+    (when e  ; can be nil, e.g. [a, ,b]
+      (js2-visit-ast e v))))
+
+(defun js2-print-array-node (n i)
+  (insert (js2-make-pad i) "[")
+  (js2-print-list (js2-array-node-elems n))
+  (insert "]"))
+
+(defstruct (js2-object-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-object-node (&key (type js2-OBJECTLIT)
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     elems)))
+  "AST node for an object literal expression."
+  elems)  ; a lisp list of `js2-object-prop-node'
+
+(put 'cl-struct-js2-object-node 'js2-visitor 'js2-visit-object-node)
+(put 'cl-struct-js2-object-node 'js2-printer 'js2-print-object-node)
+
+(defun js2-visit-object-node (n v)
+  (dolist (e (js2-object-node-elems n))
+    (js2-visit-ast e v)))
+
+(defun js2-print-object-node (n i)
+  (insert (js2-make-pad i) "{")
+  (js2-print-list (js2-object-node-elems n))
+  (insert "}"))
+
+(defstruct (js2-object-prop-node
+            (:include js2-infix-node)
+            (:constructor nil)
+            (:constructor make-js2-object-prop-node (&key (type js2-COLON)
+                                                          (pos js2-ts-cursor)
+                                                          len
+                                                          left
+                                                          right
+                                                          op-pos)))
+  "AST node for an object literal prop:value entry.
+The `left' field is the property:  a name node, string node or number node.
+The `right' field is a `js2-node' representing the initializer value.")
+
+(put 'cl-struct-js2-object-prop-node 'js2-visitor 'js2-visit-infix-node)
+(put 'cl-struct-js2-object-prop-node 'js2-printer 'js2-print-object-prop-node)
+
+(defun js2-print-object-prop-node (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-object-prop-node-left n) 0)
+  (insert ":")
+  (js2-print-ast (js2-object-prop-node-right n) 0))
+
+(defstruct (js2-getter-setter-node
+            (:include js2-infix-node)
+            (:constructor nil)
+            (:constructor make-js2-getter-setter-node (&key type ; GET or SET
+                                                            (pos js2-ts-cursor)
+                                                            len
+                                                            left
+                                                            right)))
+  "AST node for a getter/setter property in an object literal.
+The `left' field is the `js2-name-node' naming the getter/setter prop.
+The `right' field is always an anonymous `js2-function-node' with a node
+property `GETTER_SETTER' set to js2-GET or js2-SET. ")
+
+(put 'cl-struct-js2-getter-setter-node 'js2-visitor 'js2-visit-infix-node)
+(put 'cl-struct-js2-getter-setter-node 'js2-printer 'js2-print-getter-setter)
+
+(defun js2-print-getter-setter (n i)
+  (let ((pad (js2-make-pad i))
+        (left (js2-getter-setter-node-left n))
+        (right (js2-getter-setter-node-right n)))
+    (insert pad)
+    (insert (if (= (js2-node-type n) js2-GET) "get " "set "))
+    (js2-print-ast left 0)
+    (js2-print-ast right 0)))
+
+(defstruct (js2-prop-get-node
+            (:include js2-infix-node)
+            (:constructor nil)
+            (:constructor make-js2-prop-get-node (&key (type js2-GETPROP)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       left
+                                                       right)))
+  "AST node for a dotted property reference, e.g. foo.bar or foo().bar")
+
+(put 'cl-struct-js2-prop-get-node 'js2-visitor 'js2-visit-prop-get-node)
+(put 'cl-struct-js2-prop-get-node 'js2-printer 'js2-print-prop-get-node)
+
+(defun js2-visit-prop-get-node (n v)
+  (when (js2-prop-get-node-left n)
+    (js2-visit-ast (js2-prop-get-node-left n) v))
+  (when (js2-prop-get-node-right n)
+    (js2-visit-ast (js2-prop-get-node-right n) v)))
+
+(defun js2-print-prop-get-node (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-prop-get-node-left n) 0)
+  (insert ".")
+  (js2-print-ast (js2-prop-get-node-right n) 0))
+
+(defstruct (js2-elem-get-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-elem-get-node (&key (type js2-GETELEM)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       target
+                                                       element
+                                                       lb
+                                                       rb)))
+  "AST node for an array index expression such as foo[bar]."
+  target  ; a `js2-node' - the expression preceding the "."
+  element ; a `js2-node' - the expression in brackets
+  lb      ; position of left-bracket, nil if omitted
+  rb)     ; position of right-bracket, nil if omitted
+
+(put 'cl-struct-js2-elem-get-node 'js2-visitor 'js2-visit-elem-get-node)
+(put 'cl-struct-js2-elem-get-node 'js2-printer 'js2-print-elem-get-node)
+
+(defun js2-visit-elem-get-node (n v)
+  (when (js2-elem-get-node-target n)
+    (js2-visit-ast (js2-elem-get-node-target n) v))
+  (when (js2-elem-get-node-element n)
+    (js2-visit-ast (js2-elem-get-node-element n) v)))
+
+(defun js2-print-elem-get-node (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-elem-get-node-target n) 0)
+  (insert "[")
+  (js2-print-ast (js2-elem-get-node-element n) 0)
+  (insert "]"))
+
+(defstruct (js2-call-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-call-node (&key (type js2-CALL)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   target
+                                                   args
+                                                   lp
+                                                   rp)))
+  "AST node for a JavaScript function call."
+  target  ; a `js2-node' evaluating to the function to call
+  args  ; a lisp list of `js2-node' arguments
+  lp    ; position of open-paren, or nil if missing
+  rp)   ; position of close-paren, or nil if missing
+
+(put 'cl-struct-js2-call-node 'js2-visitor 'js2-visit-call-node)
+(put 'cl-struct-js2-call-node 'js2-printer 'js2-print-call-node)
+
+(defun js2-visit-call-node (n v)
+  (js2-visit-ast (js2-call-node-target n) v)
+  (dolist (arg (js2-call-node-args n))
+    (js2-visit-ast arg v)))
+
+(defun js2-print-call-node (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-call-node-target n) 0)
+  (insert "(")
+  (js2-print-list (js2-call-node-args n))
+  (insert ")"))
+
+(defstruct (js2-yield-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-yield-node (&key (type js2-YIELD)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    value)))
+  "AST node for yield statement or expression."
+  value) ; optional:  value to be yielded
+
+(put 'cl-struct-js2-yield-node 'js2-visitor 'js2-visit-yield-node)
+(put 'cl-struct-js2-yield-node 'js2-printer 'js2-print-yield-node)
+
+(defun js2-visit-yield-node (n v)
+  (js2-visit-ast (js2-yield-node-value n) v))
+
+(defun js2-print-yield-node (n i)
+  (insert (js2-make-pad i))
+  (insert "yield")
+  (when (js2-yield-node-value n)
+    (insert " ")
+    (js2-print-ast (js2-yield-node-value n) 0)))
+
+(defstruct (js2-paren-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-paren-node (&key (type js2-LP)
+                                                    (pos js2-ts-cursor)
+                                                    len
+                                                    expr)))
+  "AST node for a parenthesized expression.
+In particular, used when the parens are syntactically optional,
+as opposed to required parens such as those enclosing an if-conditional."
+  expr)   ; `js2-node'
+
+(put 'cl-struct-js2-paren-node 'js2-visitor 'js2-visit-paren-node)
+(put 'cl-struct-js2-paren-node 'js2-printer 'js2-print-paren-node)
+
+(defun js2-visit-paren-node (n v)
+  (js2-visit-ast (js2-paren-node-expr n) v))
+
+(defun js2-print-paren-node (n i)
+  (insert (js2-make-pad i))
+  (insert "(")
+  (js2-print-ast (js2-paren-node-expr n) 0)
+  (insert ")"))
+
+(defstruct (js2-array-comp-node
+            (:include js2-scope)
+            (:constructor nil)
+            (:constructor make-js2-array-comp-node (&key (type js2-ARRAYCOMP)
+                                                         (pos js2-ts-cursor)
+                                                         len
+                                                         result
+                                                         loops
+                                                         filter
+                                                         if-pos
+                                                         lp
+                                                         rp)))
+  "AST node for an Array comprehension such as [[x,y] for (x in foo) for (y in 
bar)]."
+  result  ; result expression (just after left-bracket)
+  loops   ; a lisp list of `js2-array-comp-loop-node'
+  filter  ; guard/filter expression
+  if-pos  ; buffer pos of 'if' keyword, if present, else nil
+  lp      ; buffer position of if-guard left-paren, or nil if not present
+  rp)     ; buffer position of if-guard right-paren, or nil if not present
+
+(put 'cl-struct-js2-array-comp-node 'js2-visitor 'js2-visit-array-comp-node)
+(put 'cl-struct-js2-array-comp-node 'js2-printer 'js2-print-array-comp-node)
+
+(defun js2-visit-array-comp-node (n v)
+  (js2-visit-ast (js2-array-comp-node-result n) v)
+  (dolist (l (js2-array-comp-node-loops n))
+    (js2-visit-ast l v))
+  (if (js2-array-comp-node-filter n)
+      (js2-visit-ast (js2-array-comp-node-filter n) v)))
+
+(defun js2-print-array-comp-node (n i)
+  (let ((pad (js2-make-pad i))
+        (result (js2-array-comp-node-result n))
+        (loops (js2-array-comp-node-loops n))
+        (filter (js2-array-comp-node-filter n)))
+    (insert pad "[")
+    (js2-print-ast result 0)
+    (dolist (l loops)
+      (insert " ")
+      (js2-print-ast l 0))
+    (when filter
+      (insert " if (")
+      (js2-print-ast filter 0))
+    (insert ")]")))
+
+(defstruct (js2-array-comp-loop-node
+            (:include js2-for-in-node)
+            (:constructor nil)
+            (:constructor make-js2-array-comp-loop-node (&key (type js2-FOR)
+                                                              (pos 
js2-ts-cursor)
+                                                              len
+                                                              iterator
+                                                              object
+                                                              in-pos
+                                                              foreach-p
+                                                              each-pos
+                                                              lp
+                                                              rp)))
+  "AST subtree for each 'for (foo in bar)' loop in an array comprehension.")
+
+(put 'cl-struct-js2-array-comp-loop-node 'js2-visitor 
'js2-visit-array-comp-loop)
+(put 'cl-struct-js2-array-comp-loop-node 'js2-printer 
'js2-print-array-comp-loop)
+
+(defun js2-visit-array-comp-loop (n v)
+  (js2-visit-ast (js2-array-comp-loop-node-iterator n) v)
+  (js2-visit-ast (js2-array-comp-loop-node-object n) v))
+
+(defun js2-print-array-comp-loop (n i)
+  (insert "for (")
+  (js2-print-ast (js2-array-comp-loop-node-iterator n) 0)
+  (insert " in ")
+  (js2-print-ast (js2-array-comp-loop-node-object n) 0)
+  (insert ")"))
+
+(defstruct (js2-empty-expr-node
+            (:include js2-node)
+            (:constructor nil)
+            (:constructor make-js2-empty-expr-node (&key (type js2-EMPTY)
+                                                         (pos js2-token-beg)
+                                                         len)))
+  "AST node for an empty expression.")
+
+(put 'cl-struct-js2-empty-expr-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-empty-expr-node 'js2-printer 'js2-print-none)
+
+(defstruct (js2-xml-node
+            (:include js2-block-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-node (&key (type js2-XML)
+                                                  (pos js2-token-beg)
+                                                  len
+                                                  kids)))
+  "AST node for initial parse of E4X literals.
+The kids field is a list of XML fragments, each a `js2-string-node' or
+a `js2-xml-js-expr-node'.  Equivalent to Rhino's XmlLiteral node.")
+
+(put 'cl-struct-js2-xml-node 'js2-visitor 'js2-visit-block)
+(put 'cl-struct-js2-xml-node 'js2-printer 'js2-print-xml-node)
+
+(defun js2-print-xml-node (n i)
+  (dolist (kid (js2-xml-node-kids n))
+    (js2-print-ast kid i)))
+
+(defstruct (js2-xml-js-expr-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-js-expr-node (&key (type js2-XML)
+                                                          (pos js2-ts-cursor)
+                                                          len
+                                                          expr)))
+  "AST node for an embedded JavaScript {expression} in an E4X literal.
+The start and end fields correspond to the curly-braces."
+  expr)  ; a `js2-expr-node' of some sort
+
+(put 'cl-struct-js2-xml-js-expr-node 'js2-visitor 'js2-visit-xml-js-expr)
+(put 'cl-struct-js2-xml-js-expr-node 'js2-printer 'js2-print-xml-js-expr)
+
+(defun js2-visit-xml-js-expr (n v)
+  (js2-visit-ast (js2-xml-js-expr-node-expr n) v))
+
+(defun js2-print-xml-js-expr (n i)
+  (insert (js2-make-pad i))
+  (insert "{")
+  (js2-print-ast (js2-xml-js-expr-node-expr n) 0)
+  (insert "}"))
+
+(defstruct (js2-xml-dot-query-node
+            (:include js2-infix-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-dot-query-node (&key (type js2-DOTQUERY)
+                                                            (pos js2-ts-cursor)
+                                                            op-pos
+                                                            len
+                                                            left
+                                                            right
+                                                            rp)))
+  "AST node for an E4X foo.(bar) filter expression.
+Note that the left-paren is automatically the character immediately
+following the dot (.) in the operator.  No whitespace is permitted
+between the dot and the lp by the scanner."
+  rp)
+
+(put 'cl-struct-js2-xml-dot-query-node 'js2-visitor 'js2-visit-infix-node)
+(put 'cl-struct-js2-xml-dot-query-node 'js2-printer 'js2-print-xml-dot-query)
+
+(defun js2-print-xml-dot-query (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-xml-dot-query-node-left n) 0)
+  (insert ".(")
+  (js2-print-ast (js2-xml-dot-query-node-right n) 0)
+  (insert ")"))
+
+(defstruct (js2-xml-ref-node
+            (:include js2-node)
+            (:constructor nil))  ; abstract
+  "Base type for E4X XML attribute-access or property-get expressions.
+Such expressions can take a variety of forms.  The general syntax has
+three parts:
+
+  - (optional) an @ (specifying an attribute access)
+  - (optional) a namespace (a `js2-name-node') and double-colon
+  - (required) either a `js2-name-node' or a bracketed [expression]
+
+The property-name expressions (examples:  ns::name, @name) are
+represented as `js2-xml-prop-ref' nodes.  The bracketed-expression
+versions (examples:  ns::[name], @[name]) become `js2-xml-elem-ref' nodes.
+
+This node type (or more specifically, its subclasses) will sometimes
+be the right-hand child of a `js2-prop-get-node' or a
+`js2-infix-node' of type `js2-DOTDOT', the .. xml-descendants operator.
+The `js2-xml-ref-node' may also be a standalone primary expression with
+no explicit target, which is valid in certain expression contexts such as
+
+  company..employee.(@id < 100)
+
+in this case, the @id is a `js2-xml-ref' that is part of an infix '<'
+expression whose parent is a `js2-xml-dot-query-node'."
+  namespace
+  at-pos
+  colon-pos)
+
+(defsubst js2-xml-ref-node-attr-access-p (node)
+  "Return non-nil if this expression began with an @-token."
+  (and (numberp (js2-xml-ref-node-at-pos node))
+       (plusp (js2-xml-ref-node-at-pos node))))
+
+(defstruct (js2-xml-prop-ref-node
+            (:include js2-xml-ref-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-prop-ref-node (&key (type js2-REF_NAME)
+                                                           (pos js2-token-beg)
+                                                           len
+                                                           propname
+                                                           namespace
+                                                           at-pos
+                                                           colon-pos)))
+  "AST node for an E4X XML [expr] property-ref expression.
+The JavaScript syntax is an optional @, an optional ns::, and a name.
+
+  [ '@' ] [ name '::' ] name
+
+Examples include name, ns::name, ns::*, *::name, *::*, @attr, @ns::attr,
address@hidden::*, @*::attr, @*::*, and @*.
+
+The node starts at the @ token, if present.  Otherwise it starts at the
+namespace name.  The node bounds extend through the closing right-bracket,
+or if it is missing due to a syntax error, through the end of the index
+expression."
+  propname)
+
+(put 'cl-struct-js2-xml-prop-ref-node 'js2-visitor 
'js2-visit-xml-prop-ref-node)
+(put 'cl-struct-js2-xml-prop-ref-node 'js2-printer 
'js2-print-xml-prop-ref-node)
+
+(defun js2-visit-xml-prop-ref-node (n v)
+  (if (js2-xml-prop-ref-node-namespace n)
+      (js2-visit-ast (js2-xml-prop-ref-node-namespace n) v))
+  (if (js2-xml-prop-ref-node-propname n)
+      (js2-visit-ast (js2-xml-prop-ref-node-propname n) v)))
+
+(defun js2-print-xml-prop-ref-node (n i)
+  (insert (js2-make-pad i))
+  (if (js2-xml-ref-node-attr-access-p n)
+      (insert "@"))
+  (when (js2-xml-prop-ref-node-namespace n)
+    (js2-print-ast (js2-xml-prop-ref-node-namespace n) 0)
+    (insert "::"))
+  (if (js2-xml-prop-ref-node-propname n)
+      (js2-print-ast (js2-xml-prop-ref-node-propname n) 0)))
+
+(defstruct (js2-xml-elem-ref-node
+            (:include js2-xml-ref-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-elem-ref-node (&key (type 
js2-REF_MEMBER)
+                                                           (pos js2-token-beg)
+                                                           len
+                                                           expr
+                                                           lb
+                                                           rb
+                                                           namespace
+                                                           at-pos
+                                                           colon-pos)))
+  "AST node for an E4X XML [expr] member-ref expression.
+Syntax:
+
+ [ '@' ] [ name '::' ] '[' expr ']'
+
+Examples include ns::[expr], @ns::[expr], @[expr], *::[expr] and @*::[expr].
+
+Note that the form [expr] (i.e. no namespace or attribute-qualifier)
+is not a legal E4X XML element-ref expression, since it's already used
+for standard JavaScript element-get array indexing.  Hence, a
+`js2-xml-elem-ref-node' always has either the attribute-qualifier, a
+non-nil namespace node, or both.
+
+The node starts at the @ token, if present.  Otherwise it starts
+at the namespace name.  The node bounds extend through the closing
+right-bracket, or if it is missing due to a syntax error, through the
+end of the index expression."
+  expr  ; the bracketed index expression
+  lb
+  rb)
+
+(put 'cl-struct-js2-xml-elem-ref-node 'js2-visitor 
'js2-visit-xml-elem-ref-node)
+(put 'cl-struct-js2-xml-elem-ref-node 'js2-printer 
'js2-print-xml-elem-ref-node)
+
+(defun js2-visit-xml-elem-ref-node (n v)
+  (if (js2-xml-elem-ref-node-namespace n)
+      (js2-visit-ast (js2-xml-elem-ref-node-namespace n) v))
+  (if (js2-xml-elem-ref-node-expr n)
+      (js2-visit-ast (js2-xml-elem-ref-node-expr n) v)))
+
+(defun js2-print-xml-elem-ref-node (n i)
+  (insert (js2-make-pad i))
+  (if (js2-xml-ref-node-attr-access-p n)
+      (insert "@"))
+  (when (js2-xml-elem-ref-node-namespace n)
+    (js2-print-ast (js2-xml-elem-ref-node-namespace n) 0)
+    (insert "::"))
+  (insert "[")
+  (if (js2-xml-elem-ref-node-expr n)
+      (js2-print-ast (js2-xml-elem-ref-node-expr n) 0))
+  (insert "]"))
+
+;;; Placeholder nodes for when we try parsing the XML literals structurally.
+
+(defstruct (js2-xml-start-tag-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-start-tag-node (&key (type js2-XML)
+                                                            (pos js2-ts-cursor)
+                                                            len
+                                                            name
+                                                            attrs
+                                                            kids
+                                                            empty-p)))
+  "AST node for an XML start-tag.  Not currently used.
+The `kids' field is a lisp list of child content nodes."
+  name      ; a `js2-xml-name-node'
+  attrs     ; a lisp list of `js2-xml-attr-node'
+  empty-p)  ; t if this is an empty element such as <foo bar="baz"/>
+
+(put 'cl-struct-js2-xml-start-tag-node 'js2-visitor 'js2-visit-xml-start-tag)
+(put 'cl-struct-js2-xml-start-tag-node 'js2-printer 'js2-print-xml-start-tag)
+
+(defun js2-visit-xml-start-tag (n v)
+  (js2-visit-ast (js2-xml-start-tag-node-name n) v)
+  (dolist (attr (js2-xml-start-tag-node-attrs n))
+    (js2-visit-ast attr v))
+  (js2-visit-block n v))
+
+(defun js2-print-xml-start-tag (n i)
+  (insert (js2-make-pad i) "<")
+  (js2-print-ast (js2-xml-start-tag-node-name n) 0)
+  (when (js2-xml-start-tag-node-attrs n)
+    (insert " ")
+    (js2-print-list (js2-xml-start-tag-node-attrs n) " "))
+  (insert ">"))
+
+;; I -think- I'm going to make the parent node the corresponding start-tag,
+;; and add the end-tag to the kids list of the parent as well.
+(defstruct (js2-xml-end-tag-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-end-tag-node (&key (type js2-XML)
+                                                          (pos js2-ts-cursor)
+                                                          len
+                                                          name)))
+  "AST node for an XML end-tag.  Not currently used."
+  name)  ; a `js2-xml-name-node'
+
+(put 'cl-struct-js2-xml-end-tag-node 'js2-visitor 'js2-visit-xml-end-tag)
+(put 'cl-struct-js2-xml-end-tag-node 'js2-printer 'js2-print-xml-end-tag)
+
+(defun js2-visit-xml-end-tag (n v)
+  (js2-visit-ast (js2-xml-end-tag-node-name n) v))
+
+(defun js2-print-xml-end-tag (n i)
+  (insert (js2-make-pad i))
+  (insert "</")
+  (js2-print-ast (js2-xml-end-tag-node-name n) 0)
+  (insert ">"))
+
+(defstruct (js2-xml-name-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-name-node (&key (type js2-XML)
+                                                       (pos js2-ts-cursor)
+                                                       len
+                                                       namespace
+                                                       kids)))
+  "AST node for an E4X XML name.  Not currently used.
+Any XML name can be qualified with a namespace, hence the namespace field.
+Further, any E4X name can be comprised of arbitrary JavaScript {} expressions.
+The kids field is a list of `js2-name-node' and `js2-xml-js-expr-node'.
+For a simple name, the kids list has exactly one node, a `js2-name-node'."
+  namespace)  ; a `js2-string-node'
+
+(put 'cl-struct-js2-xml-name-node 'js2-visitor 'js2-visit-xml-name-node)
+(put 'cl-struct-js2-xml-name-node 'js2-printer 'js2-print-xml-name-node)
+
+(defun js2-visit-xml-name-node (n v)
+  (js2-visit-ast (js2-xml-name-node-namespace n) v))
+
+(defun js2-print-xml-name-node (n i)
+  (insert (js2-make-pad i))
+  (when (js2-xml-name-node-namespace n)
+    (js2-print-ast (js2-xml-name-node-namespace n) 0)
+    (insert "::"))
+  (dolist (kid (js2-xml-name-node-kids n))
+    (js2-print-ast kid 0)))
+
+(defstruct (js2-xml-pi-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-pi-node (&key (type js2-XML)
+                                                     (pos js2-ts-cursor)
+                                                     len
+                                                     name
+                                                     attrs)))
+  "AST node for an E4X XML processing instruction.  Not currently used."
+  name   ; a `js2-xml-name-node'
+  attrs) ; a list of `js2-xml-attr-node'
+
+(put 'cl-struct-js2-xml-pi-node 'js2-visitor 'js2-visit-xml-pi-node)
+(put 'cl-struct-js2-xml-pi-node 'js2-printer 'js2-print-xml-pi-node)
+
+(defun js2-visit-xml-pi-node (n v)
+  (js2-visit-ast (js2-xml-pi-node-name n) v)
+  (dolist (attr (js2-xml-pi-node-attrs n))
+    (js2-visit-ast attr v)))
+
+(defun js2-print-xml-pi-node (n i)
+  (insert (js2-make-pad i) "<?")
+  (js2-print-ast (js2-xml-pi-node-name n))
+  (when (js2-xml-pi-node-attrs n)
+    (insert " ")
+    (js2-print-list (js2-xml-pi-node-attrs n)))
+  (insert "?>"))
+
+(defstruct (js2-xml-cdata-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-cdata-node (&key (type js2-XML)
+                                                        (pos js2-ts-cursor)
+                                                        len
+                                                        content)))
+  "AST node for a CDATA escape section.  Not currently used."
+  content)  ; a `js2-string-node' with node-property 'quote-type 'cdata
+
+(put 'cl-struct-js2-xml-cdata-node 'js2-visitor 'js2-visit-xml-cdata-node)
+(put 'cl-struct-js2-xml-cdata-node 'js2-printer 'js2-print-xml-cdata-node)
+
+(defun js2-visit-xml-cdata-node (n v)
+  (js2-visit-ast (js2-xml-cdata-node-content n) v))
+
+(defun js2-print-xml-cdata-node (n i)
+  (insert (js2-make-pad i))
+  (js2-print-ast (js2-xml-cdata-node-content n)))
+
+(defstruct (js2-xml-attr-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-attr-node (&key (type js2-XML)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   name
+                                                   value
+                                                   eq-pos
+                                                   quote-type)))
+  "AST node representing a foo='bar' XML attribute value.  Not yet used."
+  name   ; a `js2-xml-name-node'
+  value  ; a `js2-xml-name-node'
+  eq-pos ; buffer position of "=" sign
+  quote-type) ; 'single or 'double
+
+(put 'cl-struct-js2-xml-attr-node 'js2-visitor 'js2-visit-xml-attr-node)
+(put 'cl-struct-js2-xml-attr-node 'js2-printer 'js2-print-xml-attr-node)
+
+(defun js2-visit-xml-attr-node (n v)
+  (js2-visit-ast (js2-xml-attr-node-name n) v)
+  (js2-visit-ast (js2-xml-attr-node-value n) v))
+
+(defun js2-print-xml-attr-node (n i)
+  (let ((quote (if (eq (js2-xml-attr-node-quote-type n) 'single)
+                   "'"
+                 "\"")))
+    (insert (js2-make-pad i))
+    (js2-print-ast (js2-xml-attr-node-name n) 0)
+    (insert "=" quote)
+    (js2-print-ast (js2-xml-attr-node-value n) 0)
+    (insert quote)))
+
+(defstruct (js2-xml-text-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-text-node (&key (type js2-XML)
+                                                   (pos js2-ts-cursor)
+                                                   len
+                                                   content)))
+  "AST node for an E4X XML text node.  Not currently used."
+  content)  ; a lisp list of `js2-string-node' and `js2-xml-js-expr-node'
+
+(put 'cl-struct-js2-xml-text-node 'js2-visitor 'js2-visit-xml-text-node)
+(put 'cl-struct-js2-xml-text-node 'js2-printer 'js2-print-xml-text-node)
+
+(defun js2-visit-xml-text-node (n v)
+  (js2-visit-ast (js2-xml-text-node-content n) v))
+
+(defun js2-print-xml-text-node (n i)
+  (insert (js2-make-pad i))
+  (dolist (kid (js2-xml-text-node-content n))
+    (js2-print-ast kid)))
+
+(defstruct (js2-xml-comment-node
+            (:include js2-xml-node)
+            (:constructor nil)
+            (:constructor make-js2-xml-comment-node (&key (type js2-XML)
+                                                          (pos js2-ts-cursor)
+                                                          len)))
+  "AST node for E4X XML comment.  Not currently used.")
+
+(put 'cl-struct-js2-xml-comment-node 'js2-visitor 'js2-visit-none)
+(put 'cl-struct-js2-xml-comment-node 'js2-printer 'js2-print-xml-comment)
+
+(defun js2-print-xml-comment (n i)
+  (insert (js2-make-pad i)
+          (js2-node-string n)))
+
+;;; Node utilities
+
+(defsubst js2-node-line (n)
+  "Fetch the source line number at the start of node N.
+This is O(n) in the length of the source buffer; use prudently."
+  (1+ (count-lines (point-min) (js2-node-abs-pos n))))
+
+(defsubst js2-block-node-kid (n i)
+  "Return child I of node N, or nil if there aren't that many."
+  (nth i (js2-block-node-kids n)))
+
+(defsubst js2-block-node-first (n)
+  "Return first child of block node N, or nil if there is none."
+  (first (js2-block-node-kids n)))
+
+(defun js2-node-root (n)
+  "Return the root of the AST containing N.
+If N has no parent pointer, returns N."
+  (let ((parent (js2-node-parent n)))
+    (if parent
+        (js2-node-root parent)
+      n)))
+
+(defun js2-node-position-in-parent (node &optional parent)
+  "Return the position of NODE in parent's block-kids list.
+PARENT can be supplied if known.  Positioned returned is zero-indexed.
+Returns 0 if NODE is not a child of a block statement, or if NODE
+is not a statement node."
+  (let ((p (or parent (js2-node-parent node)))
+        (i 0))
+    (if (not (js2-block-node-p p))
+        i
+      (or (js2-position node (js2-block-node-kids p))
+          0))))
+
+(defsubst js2-node-short-name (n)
+  "Return the short name of node N as a string, e.g. `js2-if-node'."
+  (substring (symbol-name (aref n 0))
+             (length "cl-struct-")))
+
+(defsubst js2-node-child-list (node)
+  "Return the child list for NODE, a lisp list of nodes.
+Works for block nodes, array nodes, obj literals, funarg lists,
+var decls and try nodes (for catch clauses).  Note that you should call
+`js2-block-node-kids' on the function body for the body statements.
+Returns nil for zero-length child lists or unsupported nodes."
+  (cond
+   ((js2-function-node-p node)
+    (js2-function-node-params node))
+   ((js2-block-node-p node)
+    (js2-block-node-kids node))
+   ((js2-try-node-p node)
+    (js2-try-node-catch-clauses node))
+   ((js2-array-node-p node)
+    (js2-array-node-elems node))
+   ((js2-object-node-p node)
+    (js2-object-node-elems node))
+   ((js2-call-node-p node)
+    (js2-call-node-args node))
+   ((js2-new-node-p node)
+    (js2-new-node-args node))
+   ((js2-var-decl-node-p node)
+    (js2-var-decl-node-kids node))
+   (t
+    nil)))
+
+(defsubst js2-node-set-child-list (node kids)
+  "Set the child list for NODE to KIDS."
+   (cond
+    ((js2-function-node-p node)
+     (setf (js2-function-node-params node) kids))
+    ((js2-block-node-p node)
+     (setf (js2-block-node-kids node) kids))
+    ((js2-try-node-p node)
+     (setf (js2-try-node-catch-clauses node) kids))
+    ((js2-array-node-p node)
+     (setf (js2-array-node-elems node) kids))
+    ((js2-object-node-p node)
+     (setf (js2-object-node-elems node) kids))
+    ((js2-call-node-p node)
+     (setf (js2-call-node-args node) kids))
+    ((js2-new-node-p node)
+     (setf (js2-new-node-args node) kids))
+    ((js2-var-decl-node-p node)
+     (setf (js2-var-decl-node-kids node) kids))
+    (t
+     (error "Unsupported node type: %s" (js2-node-short-name node))))
+   kids)
+
+;; All because Common Lisp doesn't support multiple inheritance for defstructs.
+(defconst js2-paren-expr-nodes
+  '(cl-struct-js2-array-comp-loop-node
+    cl-struct-js2-array-comp-node
+    cl-struct-js2-call-node
+    cl-struct-js2-catch-node
+    cl-struct-js2-do-node
+    cl-struct-js2-elem-get-node
+    cl-struct-js2-for-in-node
+    cl-struct-js2-for-node
+    cl-struct-js2-function-node
+    cl-struct-js2-if-node
+    cl-struct-js2-let-node
+    cl-struct-js2-new-node
+    cl-struct-js2-paren-node
+    cl-struct-js2-switch-node
+    cl-struct-js2-while-node
+    cl-struct-js2-with-node
+    cl-struct-js2-xml-dot-query-node)
+  "Node types that can have a parenthesized child expression.
+In particular, nodes that respond to `js2-node-lp' and `js2-node-rp'.")
+
+(defsubst js2-paren-expr-node-p (node)
+  "Return t for nodes that typically have a parenthesized child expression.
+Useful for computing the indentation anchors for arg-lists and conditions.
+Note that it may return a false positive, for instance when NODE is
+a `js2-new-node' and there are no arguments or parentheses."
+  (memq (aref node 0) js2-paren-expr-nodes))
+
+;; Fake polymorphism... yech.
+(defsubst js2-node-lp (node)
+  "Return relative left-paren position for NODE, if applicable.
+For `js2-elem-get-node' structs, returns left-bracket position.
+Note that the position may be nil in the case of a parse error."
+  (cond
+   ((js2-elem-get-node-p node)
+    (js2-elem-get-node-lb node))
+   ((js2-loop-node-p node)
+    (js2-loop-node-lp node))
+   ((js2-function-node-p node)
+    (js2-function-node-lp node))
+   ((js2-if-node-p node)
+    (js2-if-node-lp node))
+   ((js2-new-node-p node)
+    (js2-new-node-lp node))
+   ((js2-call-node-p node)
+    (js2-call-node-lp node))
+   ((js2-paren-node-p node)
+    (js2-node-pos node))
+   ((js2-switch-node-p node)
+    (js2-switch-node-lp node))
+   ((js2-catch-node-p node)
+    (js2-catch-node-lp node))
+   ((js2-let-node-p node)
+    (js2-let-node-lp node))
+   ((js2-array-comp-node-p node)
+    (js2-array-comp-node-lp node))
+   ((js2-with-node-p node)
+    (js2-with-node-lp node))
+   ((js2-xml-dot-query-node-p node)
+    (1+ (js2-infix-node-op-pos node)))
+   (t
+    (error "Unsupported node type: %s" (js2-node-short-name node)))))
+
+;; Fake polymorphism... blech.
+(defsubst js2-node-rp (node)
+  "Return relative right-paren position for NODE, if applicable.
+For `js2-elem-get-node' structs, returns right-bracket position.
+Note that the position may be nil in the case of a parse error."
+  (cond
+   ((js2-elem-get-node-p node)
+    (js2-elem-get-node-lb node))
+   ((js2-loop-node-p node)
+    (js2-loop-node-rp node))
+   ((js2-function-node-p node)
+    (js2-function-node-rp node))
+   ((js2-if-node-p node)
+    (js2-if-node-rp node))
+   ((js2-new-node-p node)
+    (js2-new-node-rp node))
+   ((js2-call-node-p node)
+    (js2-call-node-rp node))
+   ((js2-paren-node-p node)
+    (+ (js2-node-pos node) (js2-node-len node)))
+   ((js2-switch-node-p node)
+    (js2-switch-node-rp node))
+   ((js2-catch-node-p node)
+    (js2-catch-node-rp node))
+   ((js2-let-node-p node)
+    (js2-let-node-rp node))
+   ((js2-array-comp-node-p node)
+    (js2-array-comp-node-rp node))
+   ((js2-with-node-p node)
+    (js2-with-node-rp node))
+   ((js2-xml-dot-query-node-p node)
+    (1+ (js2-xml-dot-query-node-rp node)))
+   (t
+    (error "Unsupported node type: %s" (js2-node-short-name node)))))
+
+(defsubst js2-node-first-child (node)
+  "Returns the first element of `js2-node-child-list' for NODE."
+  (car (js2-node-child-list node)))
+
+(defsubst js2-node-last-child (node)
+  "Returns the last element of `js2-node-last-child' for NODE."
+  (car (last (js2-node-child-list node))))
+
+(defun js2-node-prev-sibling (node)
+  "Return the previous statement in parent.
+Works for parents supported by `js2-node-child-list'.
+Returns nil if NODE is not in the parent, or PARENT is
+not a supported node, or if NODE is the first child."
+  (let* ((p (js2-node-parent node))
+         (kids (js2-node-child-list p))
+         (sib (car kids)))
+    (while (and kids
+                (not (eq node (cadr kids))))
+      (setq kids (cdr kids)
+            sib (car kids)))
+    sib))
+
+(defun js2-node-next-sibling (node)
+  "Return the next statement in parent block.
+Returns nil if NODE is not in the block, or PARENT is not
+a block node, or if NODE is the last statement."
+  (let* ((p (js2-node-parent node))
+         (kids (js2-node-child-list p)))
+    (while (and kids
+                (not (eq node (car kids))))
+      (setq kids (cdr kids)))
+    (cadr kids)))
+
+(defun js2-node-find-child-before (pos parent &optional after)
+  "Find the last child that starts before POS in parent.
+If AFTER is non-nil, returns first child starting after POS.
+POS is an absolute buffer position.  PARENT is any node
+supported by `js2-node-child-list'.
+Returns nil if no applicable child is found."
+  (let ((kids (if (js2-function-node-p parent)
+                  (js2-block-node-kids (js2-function-node-body parent))
+                (js2-node-child-list parent)))
+        (beg (if (js2-function-node-p parent)
+                 (js2-node-abs-pos (js2-function-node-body parent))
+               (js2-node-abs-pos parent)))
+        kid
+        result
+        fn
+        (continue t))
+    (setq fn (if after '> '<))
+    (while (and kids continue)
+      (setq kid (car kids))
+      (if (funcall fn (+ beg (js2-node-pos kid)) pos)
+          (setq result kid
+                continue (if after nil t))
+        (setq continue (if after t nil)))
+      (setq kids (cdr kids)))
+    result))
+
+(defun js2-node-find-child-after (pos parent)
+  "Find first child that starts after POS in parent.
+POS is an absolute buffer position.  PARENT is any node
+supported by `js2-node-child-list'.
+Returns nil if no applicable child is found."
+  (js2-node-find-child-before pos parent 'after))
+
+(defun js2-node-replace-child (pos parent new-node)
+  "Replace node at index POS in PARENT with NEW-NODE.
+Only works for parents supported by `js2-node-child-list'."
+  (let ((kids (js2-node-child-list parent))
+        (i 0))
+    (while (< i pos)
+      (setq kids (cdr kids)
+            i (1+ i)))
+    (setcar kids new-node)
+    (js2-node-add-children parent new-node)))
+
+(defun js2-node-buffer (n)
+  "Return the buffer associated with AST N.
+Returns nil if the buffer is not set as a property on the root
+node, or if parent links were not recorded during parsing."
+  (let ((root (js2-node-root n)))
+    (and root
+         (js2-ast-root-p root)
+         (js2-ast-root-buffer root))))
+
+(defsubst js2-block-node-push (n kid)
+  "Push js2-node KID onto the end of js2-block-node N's child list.
+KID is always added to the -end- of the kids list.
+Function also calls `js2-node-add-children' to add the parent link."
+  (let ((kids (js2-node-child-list n)))
+    (if kids
+        (setcdr kids (nconc (cdr kids) (list kid)))
+      (js2-node-set-child-list n (list kid)))
+    (js2-node-add-children n kid)))
+
+(defun js2-node-string (node)
+  (let ((buf (js2-node-buffer node))
+        pos)
+    (unless buf
+      (error "No buffer available for node %s" node))
+    (save-excursion
+      (set-buffer buf)
+      (buffer-substring-no-properties (setq pos (js2-node-abs-pos node))
+                                      (+ pos (js2-node-len node))))))
+
+;; Container for storing the node we're looking for in a traversal.
+(js2-deflocal js2-discovered-node nil)
+
+;; Keep track of absolute node position during traversals.
+(js2-deflocal js2-visitor-offset nil)
+
+(js2-deflocal js2-node-search-point nil)
+
+(when js2-mode-dev-mode-p
+  (defun js2-find-node-at-point ()
+    (interactive)
+    (let ((node (js2-node-at-point)))
+      (message "%s" (or node "No node found at point"))))
+  (defun js2-node-name-at-point ()
+    (interactive)
+    (let ((node (js2-node-at-point)))
+      (message "%s" (if node
+                        (js2-node-short-name node)
+                      "No node found at point.")))))
+
+(defun js2-node-at-point (&optional pos skip-comments)
+  "Return AST node at POS, a buffer position, defaulting to current point.
+The `js2-mode-ast' variable must be set to the current parse tree.
+Signals an error if the AST (`js2-mode-ast') is nil.
+Always returns a node - if it can't find one, it returns the root.
+If SKIP-COMMENTS is non-nil, comment nodes are ignored."
+  (let ((ast js2-mode-ast)
+        result)
+    (unless ast
+      (error "No JavaScript AST available"))
+    ;; Look through comments first, since they may be inside nodes that
+    ;; would otherwise report a match.
+    (setq pos (or pos (point))
+          result (if (> pos (js2-node-abs-end ast))
+                     ast
+                   (if (not skip-comments)
+                       (js2-comment-at-point pos))))
+    (unless result
+      (setq js2-discovered-node nil
+            js2-visitor-offset 0
+            js2-node-search-point pos)
+      (unwind-protect
+          (catch 'js2-visit-done
+            (js2-visit-ast ast #'js2-node-at-point-visitor))
+        (setq js2-visitor-offset nil
+              js2-node-search-point nil))
+      (setq result js2-discovered-node))
+    ;; may have found a comment beyond end of last child node,
+    ;; since visiting the ast-root looks at the comment-list last.
+    (if (and skip-comments
+             (js2-comment-node-p result))
+        (setq result nil))
+    (or result js2-mode-ast)))
+
+(defun js2-node-at-point-visitor (node end-p)
+  (let ((rel-pos (js2-node-pos node))
+        abs-pos
+        abs-end
+        (point js2-node-search-point))
+    (cond
+     (end-p
+      ;; this evaluates to a non-nil return value, even if it's zero
+      (decf js2-visitor-offset rel-pos))
+     ;; we already looked for comments before visiting, and don't want them now
+     ((js2-comment-node-p node)
+      nil)
+     (t
+      (setq abs-pos (incf js2-visitor-offset rel-pos)
+            ;; we only want to use the node if the point is before
+            ;; the last character position in the node, so we decrement
+            ;; the absolute end by 1.
+            abs-end (+ abs-pos (js2-node-len node) -1))
+      (cond
+       ;; If this node starts after search-point, stop the search.
+       ((> abs-pos point)
+        (throw 'js2-visit-done nil))
+       ;; If this node ends before the search-point, don't check kids.
+       ((> point abs-end)
+        nil)
+       (t
+        ;; Otherwise point is within this node, possibly in a child.
+        (setq js2-discovered-node node)
+        t))))))  ; keep processing kids to look for more specific match
+
+(defsubst js2-block-comment-p (node)
+  "Return non-nil if NODE is a comment node of format `jsdoc' or `block'."
+  (and (js2-comment-node-p node)
+       (memq (js2-comment-node-format node) '(jsdoc block))))
+
+;; TODO:  put the comments in a vector and binary-search them instead
+(defun js2-comment-at-point (&optional pos)
+  "Look through scanned comment nodes for one containing POS.
+POS is a buffer position that defaults to current point.
+Function returns nil if POS was not in any comment node."
+  (let ((ast js2-mode-ast)
+        (x (or pos (point)))
+        beg
+        end)
+    (unless ast
+      (error "No JavaScript AST available"))
+    (catch 'done
+      ;; Comments are stored in lexical order.
+      (dolist (comment (js2-ast-root-comments ast) nil)
+        (setq beg (js2-node-abs-pos comment)
+              end (+ beg (js2-node-len comment)))
+        (if (and (>= x beg)
+                 (<= x end))
+            (throw 'done comment))))))
+
+(defun js2-mode-find-parent-fn (node)
+  "Find function enclosing NODE.
+Returns nil if NODE is not inside a function."
+  (setq node (js2-node-parent node))
+  (while (and node (not (js2-function-node-p node)))
+    (setq node (js2-node-parent node)))
+  (and (js2-function-node-p node) node))
+
+(defun js2-mode-find-enclosing-fn (node)
+  "Find function or root enclosing NODE."
+  (if (js2-ast-root-p node)
+      node
+    (setq node (js2-node-parent node))
+    (while (not (or (js2-ast-root-p node)
+                    (js2-function-node-p node)))
+      (setq node (js2-node-parent node)))
+    node))
+
+(defun js2-mode-find-enclosing-node (beg end)
+  "Find script or function fully enclosing BEG and END."
+  (let ((node (js2-node-at-point beg))
+        pos
+        (continue t))
+    (while continue
+      (if (or (js2-ast-root-p node)
+              (and (js2-function-node-p node)
+                   (<= (setq pos (js2-node-abs-pos node)) beg)
+                   (>= (+ pos (js2-node-len node)) end)))
+          (setq continue nil)
+        (setq node (js2-node-parent node))))
+    node))
+
+(defun js2-node-parent-script-or-fn (node)
+  "Find script or function immediately enclosing NODE.
+If NODE is the ast-root, returns nil."
+  (if (js2-ast-root-p node)
+      nil
+    (setq node (js2-node-parent node))
+    (while (and node (not (or (js2-function-node-p node)
+                              (js2-script-node-p node))))
+      (setq node (js2-node-parent node)))
+    node))
+
+(defsubst js2-nested-function-p (node)
+  "Return t if NODE is a nested function, or is inside a nested function."
+  (js2-function-node-p (if (js2-function-node-p node)
+                           (js2-node-parent-script-or-fn node)
+                         (js2-node-parent-script-or-fn
+                          (js2-node-parent-script-or-fn node)))))
+
+(defsubst js2-function-param-node-p (node)
+  "Return non-nil if NODE is a param node of a `js2-function-node'."
+  (let ((parent (js2-node-parent node)))
+    (and parent
+         (js2-function-node-p parent)
+         (memq node (js2-function-node-params parent)))))
+
+(defsubst js2-mode-shift-kids (kids start offset)
+  (dolist (kid kids)
+    (if (> (js2-node-pos kid) start)
+        (incf (js2-node-pos kid) offset))))
+
+(defsubst js2-mode-shift-children (parent start offset)
+  "Update start-positions of all children of PARENT beyond START."
+  (let ((root (js2-node-root parent)))
+    (js2-mode-shift-kids (js2-node-child-list parent) start offset)
+    (js2-mode-shift-kids (js2-ast-root-comments root) start offset)))
+
+(defsubst js2-node-is-descendant (node ancestor)
+  "Return t if NODE is a descendant of ANCESTOR."
+  (while (and node
+              (not (eq node ancestor)))
+    (setq node (js2-node-parent node)))
+  node)
+
+;;; visitor infrastructure
+
+(defun js2-visit-none (node callback)
+  "Visitor for AST node that have no node children."
+  nil)
+
+(defun js2-print-none (node indent)
+  "Visitor for AST node with no printed representation.")
+
+(defun js2-print-body (node indent)
+  "Print a statement, or a block without braces."
+  (if (js2-block-node-p node)
+      (dolist (kid (js2-block-node-kids node))
+        (js2-print-ast kid indent))
+    (js2-print-ast node indent)))
+
+(defun js2-print-list (args &optional delimiter)
+  (loop with len = (length args)
+        for arg in args
+        for count from 1
+        do
+        (js2-print-ast arg 0)
+        (if (< count len)
+            (insert (or delimiter ", ")))))
+
+(defun js2-print-tree (ast)
+  "Prints an AST to the current buffer.
+Makes `js2-ast-parent-nodes' available to the printer functions."
+  (let ((max-lisp-eval-depth (max max-lisp-eval-depth 1500)))
+    (js2-print-ast ast)))
+
+(defun js2-print-ast (node &optional indent)
+  "Helper function for printing AST nodes.
+Requires `js2-ast-parent-nodes' to be non-nil.
+You should use `js2-print-tree' instead of this function."
+  (let ((printer (get (aref node 0) 'js2-printer))
+        (i (or indent 0))
+        (pos (js2-node-abs-pos node)))
+    ;; TODO:  wedge comments in here somewhere
+    (if printer
+        (funcall printer node i))))
+
+(defconst js2-side-effecting-tokens
+  (let ((tokens (make-bool-vector js2-num-tokens nil)))
+    (dolist (tt (list js2-ASSIGN
+                      js2-ASSIGN_ADD
+                      js2-ASSIGN_BITAND
+                      js2-ASSIGN_BITOR
+                      js2-ASSIGN_BITXOR
+                      js2-ASSIGN_DIV
+                      js2-ASSIGN_LSH
+                      js2-ASSIGN_MOD
+                      js2-ASSIGN_MUL
+                      js2-ASSIGN_RSH
+                      js2-ASSIGN_SUB
+                      js2-ASSIGN_URSH
+                      js2-BLOCK
+                      js2-BREAK
+                      js2-CALL
+                      js2-CATCH
+                      js2-CATCH_SCOPE
+                      js2-CONST
+                      js2-CONTINUE
+                      js2-DEBUGGER
+                      js2-DEC
+                      js2-DELPROP
+                      js2-DEL_REF
+                      js2-DO
+                      js2-ELSE
+                      js2-EMPTY
+                      js2-ENTERWITH
+                      js2-EXPORT
+                      js2-EXPR_RESULT
+                      js2-FINALLY
+                      js2-FOR
+                      js2-FUNCTION
+                      js2-GOTO
+                      js2-IF
+                      js2-IFEQ
+                      js2-IFNE
+                      js2-IMPORT
+                      js2-INC
+                      js2-JSR
+                      js2-LABEL
+                      js2-LEAVEWITH
+                      js2-LET
+                      js2-LETEXPR
+                      js2-LOCAL_BLOCK
+                      js2-LOOP
+                      js2-NEW
+                      js2-REF_CALL
+                      js2-RETHROW
+                      js2-RETURN
+                      js2-RETURN_RESULT
+                      js2-SEMI
+                      js2-SETELEM
+                      js2-SETELEM_OP
+                      js2-SETNAME
+                      js2-SETPROP
+                      js2-SETPROP_OP
+                      js2-SETVAR
+                      js2-SET_REF
+                      js2-SET_REF_OP
+                      js2-SWITCH
+                      js2-TARGET
+                      js2-THROW
+                      js2-TRY
+                      js2-VAR
+                      js2-WHILE
+                      js2-WITH
+                      js2-WITHEXPR
+                      js2-YIELD))
+      (aset tokens tt t))
+    (if js2-instanceof-has-side-effects
+        (aset tokens js2-INSTANCEOF t))
+    tokens))
+
+(defun js2-node-has-side-effects (node)
+  "Return t if NODE has side effects."
+  (when node  ; makes it easier to handle malformed expressions
+    (let ((tt (js2-node-type node)))
+      (cond
+       ;; This doubtless needs some work, since EXPR_VOID is used
+       ;; in several ways in Rhino, and I may not have caught them all.
+       ;; I'll wait for people to notice incorrect warnings.
+       ((and (= tt js2-EXPR_VOID)
+             (js2-expr-stmt-node-p node)) ; but not if EXPR_RESULT
+        (js2-node-has-side-effects (js2-expr-stmt-node-expr node)))
+       ((= tt js2-COMMA)
+        (js2-node-has-side-effects (js2-infix-node-right node)))
+       ((or (= tt js2-AND)
+            (= tt js2-OR))
+        (or (js2-node-has-side-effects (js2-infix-node-right node))
+            (js2-node-has-side-effects (js2-infix-node-left node))))
+       ((= tt js2-HOOK)
+        (and (js2-node-has-side-effects (js2-cond-node-true-expr node))
+             (js2-node-has-side-effects (js2-cond-node-false-expr node))))
+       ((js2-paren-node-p node)
+        (js2-node-has-side-effects (js2-paren-node-expr node)))
+       ((= tt js2-ERROR) ; avoid cascaded error messages
+        nil)
+       (t
+        (aref js2-side-effecting-tokens tt))))))
+
+(defun js2-member-expr-leftmost-name (node)
+  "For an expr such as foo.bar.baz, return leftmost node foo.
+NODE is any `js2-node' object.  If it represents a member expression,
+which is any sequence of property gets, element-gets, function calls,
+or xml descendants/filter operators, then we look at the lexically
+leftmost (first) node in the chain.  If it is a name-node we return it.
+Note that NODE can be a raw name-node and it will be returned as well.
+If NODE is not a name-node or member expression, or if it is a member
+expression whose leftmost target is not a name node, returns nil."
+  (let ((continue t)
+        result)
+    (while (and continue (not result))
+      (cond
+       ((js2-name-node-p node)
+        (setq result node))
+       ((js2-prop-get-node-p node)
+        (setq node (js2-prop-get-node-left node)))
+       ;; TODO:  handle call-nodes, xml-nodes, others?
+       (t
+        (setq continue nil))))
+    result))
+
+(defconst js2-stmt-node-types
+  (list js2-BLOCK
+        js2-BREAK
+        js2-CONTINUE
+        js2-DEFAULT  ; e4x "default xml namespace" statement
+        js2-DO
+        js2-EXPR_RESULT
+        js2-EXPR_VOID
+        js2-FOR
+        js2-IF
+        js2-RETURN
+        js2-SWITCH
+        js2-THROW
+        js2-TRY
+        js2-WHILE
+        js2-WITH)
+  "Node types that only appear in statement contexts.
+The list does not include nodes that always appear as the child
+of another specific statement type, such as switch-cases,
+catch and finally blocks, and else-clauses.  The list also excludes
+nodes like yield, let and var, which may appear in either expression
+or statement context, and in the latter context always have a
+`js2-expr-stmt-node' parent.  Finally, the list does not include
+functions or scripts, which are treated separately from statements
+by the JavaScript parser and runtime.")
+
+(defun js2-stmt-node-p (node)
+  "Heuristic for figuring out if NODE is a statement.
+Some node types can appear in either an expression context or a
+statement context, e.g. let-nodes, yield-nodes, and var-decl nodes.
+For these node types in a statement context, the parent will be a
+`js2-expr-stmt-node'.
+Functions aren't included in the check."
+  (memq (js2-node-type node) js2-stmt-node-types))
+
+(defsubst js2-mode-find-first-stmt (node)
+  "Search upward starting from NODE looking for a statement.
+For purposes of this function, a `js2-function-node' counts."
+  (while (not (or (js2-stmt-node-p node)
+                  (js2-function-node-p node)))
+    (setq node (js2-node-parent node)))
+  node)
+
+(defun js2-node-parent-stmt (node)
+  "Return the node's first ancestor that is a statement.
+Returns nil if NODE is a `js2-ast-root'.  Note that any expression
+appearing in a statement context will have a parent that is a
+`js2-expr-stmt-node' that will be returned by this function."
+  (let ((parent (js2-node-parent node)))
+    (if (or (null parent)
+            (js2-stmt-node-p parent)
+            (and (js2-function-node-p parent)
+                 (not (eq (js2-function-node-form parent)
+                          'FUNCTION_EXPRESSION))))
+        parent
+      (js2-node-parent-stmt parent))))
+
+;; In the Mozilla Rhino sources, Roshan James writes:
+;;  Does consistent-return analysis on the function body when strict mode is
+;;  enabled.
+;;
+;;    function (x) { return (x+1) }
+;;
+;;  is ok, but
+;;
+;;    function (x) { if (x < 0) return (x+1); }
+;;
+;;  is not because the function can potentially return a value when the
+;;  condition is satisfied and if not, the function does not explicitly
+;;  return a value.
+;;
+;;  This extends to checking mismatches such as "return" and "return <value>"
+;;  used in the same function. Warnings are not emitted if inconsistent
+;;  returns exist in code that can be statically shown to be unreachable.
+;;  Ex.
+;;    function (x) { while (true) { ... if (..) { return value } ... } }
+;;
+;;  emits no warning. However if the loop had a break statement, then a
+;;  warning would be emitted.
+;;
+;;  The consistency analysis looks at control structures such as loops, ifs,
+;;  switch, try-catch-finally blocks, examines the reachable code paths and
+;;  warns the user about an inconsistent set of termination possibilities.
+;;
+;;  These flags enumerate the possible ways a statement/function can
+;;  terminate. These flags are used by endCheck() and by the Parser to
+;;  detect inconsistent return usage.
+;;
+;;  END_UNREACHED is reserved for code paths that are assumed to always be
+;;  able to execute (example: throw, continue)
+;;
+;;  END_DROPS_OFF indicates if the statement can transfer control to the
+;;  next one. Statement such as return dont. A compound statement may have
+;;  some branch that drops off control to the next statement.
+;;
+;;  END_RETURNS indicates that the statement can return with no value.
+;;  END_RETURNS_VALUE indicates that the statement can return a value.
+;;
+;;  A compound statement such as
+;;  if (condition) {
+;;    return value;
+;;  }
+;;  Will be detected as (END_DROPS_OFF | END_RETURN_VALUE) by endCheck()
+
+(defconst js2-END_UNREACHED 0)
+(defconst js2-END_DROPS_OFF 1)
+(defconst js2-END_RETURNS 2)
+(defconst js2-END_RETURNS_VALUE 4)
+(defconst js2-END_YIELDS 8)
+
+(defun js2-has-consistent-return-usage (node)
+  "Check that every return usage in a function body is consistent.
+Returns t if the function satisfies strict mode requirement."
+  (let ((n (js2-end-check node)))
+    ;; either it doesn't return a value in any branch...
+    (or (js2-flag-not-set-p n js2-END_RETURNS_VALUE)
+        ;; or it returns a value (or is unreached) at every branch
+        (js2-flag-not-set-p n (logior js2-END_DROPS_OFF
+                                      js2-END_RETURNS
+                                      js2-END_YIELDS)))))
+
+(defun js2-end-check-if (node)
+  "Returns in the then and else blocks must be consistent with each other.
+If there is no else block, then the return statement can fall through.
+Returns logical OR of END_* flags"
+  (let ((th (js2-if-node-then-part node))
+        (el (js2-if-node-else-part node)))
+    (if (null th)
+        js2-END_UNREACHED
+      (logior (js2-end-check th) (if el
+                                     (js2-end-check el)
+                                   js2-END_DROPS_OFF)))))
+
+(defun js2-end-check-switch (node)
+  "Consistency of return statements is checked between the case statements.
+If there is no default, then the switch can fall through. If there is a
+default, we check to see if all code paths in the default return or if
+there is a code path that can fall through.
+Returns logical OR of END_* flags."
+  (let ((rv js2-END_UNREACHED)
+        default-case)
+    ;; examine the cases
+    (catch 'break
+      (dolist (c (js2-switch-node-cases node))
+        (if (js2-case-node-expr c)
+            (js2-set-flag rv (js2-end-check-block c))
+          (setq default-case c)
+          (throw 'break nil))))
+    ;; we don't care how the cases drop into each other
+    (js2-clear-flag rv js2-END_DROPS_OFF)
+    ;; examine the default
+    (js2-set-flag rv (if default-case
+                         (js2-end-check default-case)
+                       js2-END_DROPS_OFF))
+    rv))
+
+(defun js2-end-check-try (node)
+ "If the block has a finally, return consistency is checked in the
+finally block. If all code paths in the finally return, then the
+returns in the try-catch blocks don't matter. If there is a code path
+that does not return or if there is no finally block, the returns
+of the try and catch blocks are checked for mismatch.
+Returns logical OR of END_* flags."
+ (let ((finally (js2-try-node-finally-block node))
+       rv)
+   ;; check the finally if it exists
+   (setq rv (if finally
+                (js2-end-check (js2-finally-node-body finally))
+              js2-END_DROPS_OFF))
+   ;; If the finally block always returns, then none of the returns
+   ;; in the try or catch blocks matter.
+   (when (js2-flag-set-p rv js2-END_DROPS_OFF)
+     (js2-clear-flag rv js2-END_DROPS_OFF)
+     ;; examine the try block
+     (js2-set-flag rv (js2-end-check (js2-try-node-try-block node)))
+     ;; check each catch block
+     (dolist (cb (js2-try-node-catch-clauses node))
+       (js2-set-flag rv (js2-end-check (js2-catch-node-block cb)))))
+   rv))
+
+(defun js2-end-check-loop (node)
+  "Return statement in the loop body must be consistent. The default
+assumption for any kind of a loop is that it will eventually terminate.
+The only exception is a loop with a constant true condition. Code that
+follows such a loop is examined only if one can statically determine
+that there is a break out of the loop.
+
+    for(... ; ... ; ...) {}
+    for(... in ... ) {}
+    while(...) { }
+    do { } while(...)
+
+Returns logical OR of END_* flags."
+  (let ((rv (js2-end-check (js2-loop-node-body node)))
+        (condition (cond
+                    ((js2-while-node-p node)
+                     (js2-while-node-condition node))
+                     ((js2-do-node-p node)
+                      (js2-do-node-condition node))
+                     ((js2-for-node-p node)
+                      (js2-for-node-condition node)))))
+
+    ;; check to see if the loop condition is always true
+    (if (and condition
+             (eq (js2-always-defined-boolean-p condition) 'ALWAYS_TRUE))
+        (js2-clear-flag rv js2-END_DROPS_OFF))
+
+    ;; look for effect of breaks
+    (js2-set-flag rv (js2-node-get-prop node
+                                        'CONTROL_BLOCK_PROP
+                                        js2-END_UNREACHED))
+    rv))
+
+(defun js2-end-check-block (node)
+  "A general block of code is examined statement by statement.
+If any statement (even a compound one) returns in all branches, then
+subsequent statements are not examined.
+Returns logical OR of END_* flags."
+  (let* ((rv js2-END_DROPS_OFF)
+         (kids (js2-block-node-kids node))
+         (n (car kids)))
+    ;; Check each statment.  If the statement can continue onto the next
+    ;; one (i.e. END_DROPS_OFF is set), then check the next statement.
+    (while (and n (js2-flag-set-p rv js2-END_DROPS_OFF))
+      (js2-clear-flag rv js2-END_DROPS_OFF)
+      (js2-set-flag rv (js2-end-check n))
+      (setq kids (cdr kids)
+            n (car kids)))
+    rv))
+
+(defun js2-end-check-label (node)
+  "A labeled statement implies that there may be a break to the label.
+The function processes the labeled statement and then checks the
+CONTROL_BLOCK_PROP property to see if there is ever a break to the
+particular label.
+Returns logical OR of END_* flags."
+  (let ((rv (js2-end-check (js2-labeled-stmt-node-stmt node))))
+    (logior rv (js2-node-get-prop node
+                                  'CONTROL_BLOCK_PROP
+                                  js2-END_UNREACHED))))
+
+(defun js2-end-check-break (node)
+  "When a break is encountered annotate the statement being broken
+out of by setting its CONTROL_BLOCK_PROP property.
+Returns logical OR of END_* flags."
+  (and (js2-break-node-target node)
+       (js2-node-set-prop (js2-break-node-target node)
+                          'CONTROL_BLOCK_PROP
+                          js2-END_DROPS_OFF))
+  js2-END_UNREACHED)
+
+(defun js2-end-check (node)
+  "Examine the body of a function, doing a basic reachability analysis.
+Returns a combination of flags END_* flags that indicate
+how the function execution can terminate. These constitute only the
+pessimistic set of termination conditions. It is possible that at
+runtime certain code paths will never be actually taken. Hence this
+analysis will flag errors in cases where there may not be errors.
+Returns logical OR of END_* flags"
+  (let (kid)
+    (cond
+     ((js2-break-node-p node)
+      (js2-end-check-break node))
+     ((js2-expr-stmt-node-p node)
+      (if (setq kid (js2-expr-stmt-node-expr node))
+          (js2-end-check kid)
+        js2-END_DROPS_OFF))
+     ((or (js2-continue-node-p node)
+          (js2-throw-node-p node))
+      js2-END_UNREACHED)
+     ((js2-return-node-p node)
+      (if (setq kid (js2-return-node-retval node))
+          js2-END_RETURNS_VALUE
+        js2-END_RETURNS))
+     ((js2-loop-node-p node)
+      (js2-end-check-loop node))
+     ((js2-switch-node-p node)
+      (js2-end-check-switch node))
+     ((js2-labeled-stmt-node-p node)
+      (js2-end-check-label node))
+     ((js2-if-node-p node)
+      (js2-end-check-if node))
+     ((js2-try-node-p node)
+      (js2-end-check-try node))
+     ((js2-block-node-p node)
+      (if (null (js2-block-node-kids node))
+          js2-END_DROPS_OFF
+        (js2-end-check-block node)))
+     ((js2-yield-node-p node)
+      js2-END_YIELDS)
+     (t
+      js2-END_DROPS_OFF))))
+
+(defun js2-always-defined-boolean-p (node)
+  "Check if NODE always evaluates to true or false in boolean context.
+Returns 'ALWAYS_TRUE, 'ALWAYS_FALSE, or nil if it's neither always true
+nor always false."
+  (let ((tt (js2-node-type node))
+        num)
+    (cond
+     ((or (= tt js2-FALSE) (= tt js2-NULL))
+      'ALWAYS_FALSE)
+     ((= tt js2-TRUE)
+      'ALWAYS_TRUE)
+     ((= tt js2-NUMBER)
+      (setq num (js2-number-node-num-value node))
+      (if (and (not (eq num 0.0e+NaN))
+               (not (zerop num)))
+          'ALWAYS_TRUE
+        'ALWAYS_FALSE))
+     (t
+      nil))))
+
+;;; Scanner -- a port of Mozilla Rhino's lexer.
+;; Corresponds to Rhino files Token.java and TokenStream.java.
+
+(defvar js2-tokens nil
+  "List of all defined token names.")  ; initialized in `js2-token-names'
+
+(defconst js2-token-names
+  (let* ((names (make-vector js2-num-tokens -1))
+         (case-fold-search nil)  ; only match js2-UPPER_CASE
+         (syms (apropos-internal "^js2-\\(?:[A-Z_]+\\)")))
+    (loop for sym in syms
+          for i from 0
+          do
+          (unless (or (memq sym '(js2-EOF_CHAR js2-ERROR))
+                      (not (boundp sym)))
+            (aset names (symbol-value sym)         ; code, e.g. 152
+                  (substring (symbol-name sym) 4)) ; name, e.g. "LET"
+            (push sym js2-tokens)))
+    names)
+  "Vector mapping int values to token string names, sans `js2-' prefix.")
+
+(defun js2-token-name (tok)
+  "Return a string name for TOK, a token symbol or code.
+Signals an error if it's not a recognized token."
+  (let ((code tok))
+    (if (symbolp tok)
+        (setq code (symbol-value tok)))
+    (if (eq code -1)
+        "ERROR"
+      (if (and (numberp code)
+               (not (minusp code))
+               (< code js2-num-tokens))
+          (aref js2-token-names code)
+        (error "Invalid token: %s" code)))))
+
+(defsubst js2-token-sym (tok)
+  "Return symbol for TOK given its code, e.g. 'js2-LP for code 86."
+  (intern (js2-token-name tok)))
+
+(defconst js2-token-codes
+  (let ((table (make-hash-table :test 'eq :size 256)))
+    (loop for name across js2-token-names
+          for sym = (intern (concat "js2-" name))
+          do
+          (puthash sym (symbol-value sym) table))
+    ;; clean up a few that are "wrong" in Rhino's token codes
+    (puthash 'js2-DELETE js2-DELPROP table)
+    table)
+  "Hashtable mapping token symbols to their bytecodes.")
+
+(defsubst js2-token-code (sym)
+  "Return code for token symbol SYM, e.g. 86 for 'js2-LP."
+  (or (gethash sym js2-token-codes)
+      (error "Invalid token symbol: %s " sym)))  ; signal code bug
+
+(defsubst js2-report-scan-error (msg &optional no-throw beg len)
+  (setq js2-token-end js2-ts-cursor)
+  (js2-report-error msg nil
+                    (or beg js2-token-beg)
+                    (or len (- js2-token-end js2-token-beg)))
+  (unless no-throw
+    (throw 'return js2-ERROR)))
+
+(defsubst js2-get-string-from-buffer ()
+  "Reverse the char accumulator and return it as a string."
+  (setq js2-token-end js2-ts-cursor)
+  (if js2-ts-string-buffer
+      (apply #'string (nreverse js2-ts-string-buffer))
+    ""))
+
+;; TODO:  could potentially avoid a lot of consing by allocating a
+;; char buffer the way Rhino does.
+(defsubst js2-add-to-string (c)
+  (push c js2-ts-string-buffer))
+
+;; Note that when we "read" the end-of-file, we advance js2-ts-cursor
+;; to (1+ (point-max)), which lets the scanner treat end-of-file like
+;; any other character:  when it's not part of the current token, we
+;; unget it, allowing it to be read again by the following call.
+(defsubst js2-unget-char ()
+  (decf js2-ts-cursor))
+
+;; Rhino distinguishes \r and \n line endings.  We don't need to
+;; because we only scan from Emacs buffers, which always use \n.
+(defsubst js2-get-char ()
+  "Read and return the next character from the input buffer.
+Increments `js2-ts-lineno' if the return value is a newline char.
+Updates `js2-ts-cursor' to the point after the returned char.
+Returns `js2-EOF_CHAR' if we hit the end of the buffer.
+Also updates `js2-ts-hit-eof' and `js2-ts-line-start' as needed."
+  (let (c)
+    ;; check for end of buffer
+    (if (>= js2-ts-cursor (point-max))
+        (setq js2-ts-hit-eof t
+              js2-ts-cursor (1+ js2-ts-cursor)
+              c js2-EOF_CHAR)  ; return value
+      ;; otherwise read next char
+      (setq c (char-before (incf js2-ts-cursor)))
+      ;; if we read a newline, update counters
+      (if (= c ?\n)
+          (setq js2-ts-line-start js2-ts-cursor
+                js2-ts-lineno (1+ js2-ts-lineno)))
+      ;; TODO:  skip over format characters
+      c)))
+
+(defsubst js2-read-unicode-escape ()
+  "Read a \\uNNNN sequence from the input.
+Assumes the ?\ and ?u have already been read.
+Returns the unicode character, or nil if it wasn't a valid character.
+Doesn't change the values of any scanner variables."
+  ;; I really wish I knew a better way to do this, but I can't
+  ;; find the Emacs function that takes a 16-bit int and converts
+  ;; it to a Unicode/utf-8 character.  So I basically eval it with (read).
+  ;; Have to first check that it's 4 hex characters or it may stop
+  ;; the read early.
+  (ignore-errors
+    (let ((s (buffer-substring-no-properties js2-ts-cursor
+                                             (+ 4 js2-ts-cursor))))
+      (if (string-match "[a-zA-Z0-9]\\{4\\}" s)
+          (read (concat "?\\u" s))))))
+
+(defsubst js2-match-char (test)
+  "Consume and return next character if it matches TEST, a character.
+Returns nil and consumes nothing if TEST is not the next character."
+  (let ((c (js2-get-char)))
+    (if (eq c test)
+        t
+      (js2-unget-char)
+      nil)))
+
+(defsubst js2-peek-char ()
+  (prog1
+      (js2-get-char)
+    (js2-unget-char)))
+
+(defsubst js2-java-identifier-start-p (c)
+  (or
+   (memq c '(?$ ?_))
+   (js2-char-uppercase-p c)
+   (js2-char-lowercase-p c)))
+
+(defsubst js2-java-identifier-part-p (c)
+  "Implementation of java.lang.Character.isJavaIdentifierPart()"
+  ;; TODO:  make me Unicode-friendly.  See comments above.
+  (or
+   (memq c '(?$ ?_))
+   (js2-char-uppercase-p c)
+   (js2-char-lowercase-p c)
+   (and (>= c ?0) (<= c ?9))))
+
+(defsubst js2-alpha-p (c)
+  (cond ((and (<= ?A c) (<= c ?Z)) t)
+        ((and (<= ?a c) (<= c ?z)) t)
+        (t nil)))
+
+(defsubst js2-digit-p (c)
+  (and (<= ?0 c) (<= c ?9)))
+
+(defsubst js2-js-space-p (c)
+  (if (<= c 127)
+      (memq c '(#x20 #x9 #xB #xC #xD))
+    (or
+     (eq c #xA0)
+     ;; TODO:  change this nil to check for Unicode space character
+     nil)))
+
+(defconst js2-eol-chars (list js2-EOF_CHAR ?\n ?\r))
+
+(defsubst js2-skip-line ()
+  "Skip to end of line"
+  (let (c)
+    (while (not (memq (setq c (js2-get-char)) js2-eol-chars)))
+    (js2-unget-char)
+    (setq js2-token-end js2-ts-cursor)))
+
+(defun js2-init-scanner (&optional buf line)
+  "Create token stream for BUF starting on LINE.
+BUF defaults to current-buffer and line defaults to 1.
+
+A buffer can only have one scanner active at a time, which yields
+dramatically simpler code than using a defstruct.  If you need to
+have simultaneous scanners in a buffer, copy the regions to scan
+into temp buffers."
+  (save-excursion
+    (when buf
+      (set-buffer buf))
+    (setq js2-ts-dirty-line nil
+          js2-ts-regexp-flags nil
+          js2-ts-string ""
+          js2-ts-number nil
+          js2-ts-hit-eof nil
+          js2-ts-line-start 0
+          js2-ts-lineno (or line 1)
+          js2-ts-line-end-char -1
+          js2-ts-cursor (point-min)
+          js2-ts-is-xml-attribute nil
+          js2-ts-xml-is-tag-content nil
+          js2-ts-xml-open-tags-count 0
+          js2-ts-string-buffer nil)))
+
+;; This function uses the cached op, string and number fields in
+;; TokenStream; if getToken has been called since the passed token
+;; was scanned, the op or string printed may be incorrect.
+(defun js2-token-to-string (token)
+  ;; Not sure where this function is used in Rhino.  Not tested.
+  (if (not js2-debug-print-trees)
+      ""
+    (let ((name (js2-token-name token)))
+      (cond
+       ((memq token (list js2-STRING js2-REGEXP js2-NAME))
+        (concat name " `" js2-ts-string "'"))
+       ((eq token js2-NUMBER)
+        (format "NUMBER %g" js2-ts-number))
+       (t
+        name)))))
+
+(defconst js2-keywords
+  '(break
+    case catch const continue
+    debugger default delete do
+    else enum
+    false finally for function
+    if in instanceof import
+    let
+    new null
+    return
+    switch
+    this throw true try typeof
+    var void
+    while with
+    yield))
+
+;; Token names aren't exactly the same as the keywords, unfortunately.
+;; E.g. enum isn't in the tokens, and delete is js2-DELPROP.
+(defconst js2-kwd-tokens
+  (let ((table (make-vector js2-num-tokens nil))
+        (tokens
+         (list js2-BREAK
+               js2-CASE js2-CATCH js2-CONST js2-CONTINUE
+               js2-DEBUGGER js2-DEFAULT js2-DELPROP js2-DO
+               js2-ELSE
+               js2-FALSE js2-FINALLY js2-FOR js2-FUNCTION
+               js2-IF js2-IN js2-INSTANCEOF js2-IMPORT
+               js2-LET
+               js2-NEW js2-NULL
+               js2-RETURN
+               js2-SWITCH
+               js2-THIS js2-THROW js2-TRUE js2-TRY js2-TYPEOF
+               js2-VAR
+               js2-WHILE js2-WITH
+               js2-YIELD)))
+    (dolist (i tokens)
+      (aset table i 'font-lock-keyword-face))
+    (aset table js2-STRING 'font-lock-string-face)
+    (aset table js2-REGEXP 'font-lock-string-face)
+    (aset table js2-COMMENT 'font-lock-comment-face)
+    (aset table js2-THIS 'font-lock-builtin-face)
+    (aset table js2-VOID 'font-lock-constant-face)
+    (aset table js2-NULL 'font-lock-constant-face)
+    (aset table js2-TRUE 'font-lock-constant-face)
+    (aset table js2-FALSE 'font-lock-constant-face)
+    table)
+  "Vector whose values are non-nil for tokens that are keywords.
+The values are default faces to use for highlighting the keywords.")
+
+(defconst js2-reserved-words
+  '(abstract
+    boolean byte
+    char class
+    double
+    enum export extends
+    final float
+    goto
+    implements import int interface
+    long
+    native
+    package private protected public
+    short static super synchronized
+    throws transient
+    volatile))
+
+(defconst js2-keyword-names
+  (let ((table (make-hash-table :test 'equal)))
+    (loop for k in js2-keywords
+          do (puthash
+              (symbol-name k)                            ; instanceof
+              (intern (concat "js2-"
+                              (upcase (symbol-name k)))) ; js2-INSTANCEOF
+              table))
+    table)
+  "JavaScript keywords by name, mapped to their symbols.")
+
+(defconst js2-reserved-word-names
+  (let ((table (make-hash-table :test 'equal)))
+    (loop for k in js2-reserved-words
+          do
+          (puthash (symbol-name k) 'js2-RESERVED table))
+    table)
+  "JavaScript reserved words by name, mapped to 'js2-RESERVED.")
+
+(defsubst js2-collect-string (buf)
+  "Convert BUF, a list of chars, to a string.
+Reverses BUF before converting."
+  (cond
+   ((stringp buf)
+    buf)
+   ((null buf)  ; for emacs21 compat
+    "")
+   (t
+    (if buf
+        (apply #'string (nreverse buf))
+      ""))))
+
+(defun js2-string-to-keyword (s)
+  "Return token for S, a string, if S is a keyword or reserved word.
+Returns a symbol such as 'js2-BREAK, or nil if not keyword/reserved."
+  (or (gethash s js2-keyword-names)
+      (gethash s js2-reserved-word-names)))
+
+(defsubst js2-ts-set-char-token-bounds ()
+  "Used when next token is one character."
+  (setq js2-token-beg (1- js2-ts-cursor)
+        js2-token-end js2-ts-cursor))
+
+(defsubst js2-ts-return (token)
+  "Return an N-character TOKEN from `js2-get-token'.
+Updates `js2-token-end' accordingly."
+  (setq js2-token-end js2-ts-cursor)
+  (throw 'return token))
+
+(defsubst js2-x-digit-to-int (c accumulator)
+  "Build up a hex number.
+If C is a hexadecimal digit, return ACCUMULATOR * 16 plus
+corresponding number.  Otherwise return -1."
+  (catch 'return
+    (catch 'check
+      ;; Use 0..9 < A..Z < a..z
+      (cond
+       ((<= c ?9)
+        (decf c ?0)
+        (if (<= 0 c)
+            (throw 'check nil)))
+       ((<= c ?F)
+        (when (<= ?A c)
+          (decf c (- ?A 10))
+          (throw 'check nil)))
+       ((<= c ?f)
+        (when (<= ?a c)
+          (decf c (- ?a 10))
+          (throw 'check nil))))
+      (throw 'return -1))
+    (logior c (lsh accumulator 4))))
+
+(defun js2-get-token ()
+  "Return next JavaScript token, an int such as js2-RETURN."
+  (let (c
+        c1
+        identifier-start
+        is-unicode-escape-start
+        contains-escape
+        escape-val
+        escape-start
+        str
+        result
+        base
+        is-integer
+        quote-char
+        val
+        look-for-slash
+        continue)
+    (catch 'return
+      (while t
+        ;; Eat whitespace, possibly sensitive to newlines.
+        (setq continue t)
+        (while continue
+          (setq c (js2-get-char))
+          (cond
+           ((eq c js2-EOF_CHAR)
+            (js2-ts-set-char-token-bounds)
+            (throw 'return js2-EOF))
+           ((eq c ?\n)
+            (js2-ts-set-char-token-bounds)
+            (setq js2-ts-dirty-line nil)
+            (throw 'return js2-EOL))
+           ((not (js2-js-space-p c))
+            (if (/= c ?-)               ; in case end of HTML comment
+                (setq js2-ts-dirty-line t))
+            (setq continue nil))))
+        ;; Assume the token will be 1 char - fixed up below.
+        (js2-ts-set-char-token-bounds)
+        (when (eq c ?@)
+          (throw 'return js2-XMLATTR))
+        ;; identifier/keyword/instanceof?
+        ;; watch out for starting with a <backslash>
+        (cond
+         ((eq c ?\\)
+          (setq c (js2-get-char))
+          (if (eq c ?u)
+              (setq identifier-start t
+                    is-unicode-escape-start t
+                    js2-ts-string-buffer nil)
+            (setq identifier-start nil)
+            (js2-unget-char)
+            (setq c ?\\)))
+         (t
+          (when (setq identifier-start (js2-java-identifier-start-p c))
+            (setq js2-ts-string-buffer nil)
+            (js2-add-to-string c))))
+        (when identifier-start
+          (setq contains-escape is-unicode-escape-start)
+          (catch 'break
+            (while t
+              (if is-unicode-escape-start
+                  ;; strictly speaking we should probably push-back
+                  ;; all the bad characters if the <backslash>uXXXX
+                  ;; sequence is malformed. But since there isn't a
+                  ;; correct context(is there?) for a bad Unicode
+                  ;; escape sequence in an identifier, we can report
+                  ;; an error here.
+                  (progn
+                    (setq escape-val 0)
+                    (dotimes (i 4)
+                      (setq c (js2-get-char)
+                            escape-val (js2-x-digit-to-int c escape-val))
+                      ;; Next check takes care of c < 0 and bad escape
+                      (if (minusp escape-val)
+                          (throw 'break nil)))
+                    (if (minusp escape-val)
+                        (js2-report-scan-error "msg.invalid.escape" t))
+                    (js2-add-to-string escape-val)
+                    (setq is-unicode-escape-start nil))
+                (setq c (js2-get-char))
+                (cond
+                 ((eq c ?\\)
+                  (setq c (js2-get-char))
+                  (if (eq c ?u)
+                      (setq is-unicode-escape-start t
+                            contains-escape t)
+                    (js2-report-scan-error "msg.illegal.character" t)))
+                 (t
+                  (if (or (eq c js2-EOF_CHAR)
+                          (not (js2-java-identifier-part-p c)))
+                      (throw 'break nil))
+                  (js2-add-to-string c))))))
+          (js2-unget-char)
+          (setq str (js2-get-string-from-buffer))
+          (unless contains-escape
+            ;; OPT we shouldn't have to make a string (object!) to
+            ;; check if it's a keyword.
+            ;; Return the corresponding token if it's a keyword
+            (when (setq result (js2-string-to-keyword str))
+              (if (and (< js2-language-version 170)
+                       (memq result '(js2-LET js2-YIELD)))
+                  ;; LET and YIELD are tokens only in 1.7 and later
+                  (setq result 'js2-NAME))
+              (if (not (eq result js2-RESERVED))
+                  (throw 'return (js2-token-code result)))
+              (js2-report-warning "msg.reserved.keyword" str)))
+          ;; If we want to intern these as Rhino does, just use (intern str)
+          (setq js2-ts-string str)
+          (throw 'return js2-NAME))     ; end identifier/kwd check
+        ;; is it a number?
+        (when (or (js2-digit-p c)
+                  (and (eq c ?.) (js2-digit-p (js2-peek-char))))
+          (setq js2-ts-string-buffer nil
+                base 10)
+          (when (eq c ?0)
+            (setq c (js2-get-char))
+            (cond
+             ((or (eq c ?x) (eq c ?X))
+              (setq base 16)
+              (setq c (js2-get-char)))
+             ((js2-digit-p c)
+              (setq base 8))
+             (t
+              (js2-add-to-string ?0))))
+          (if (eq base 16)
+              (while (<= 0 (js2-x-digit-to-int c 0))
+                (js2-add-to-string c)
+                (setq c (js2-get-char)))
+            (while (and (<= ?0 c) (<= c ?9))
+              ;; We permit 08 and 09 as decimal numbers, which
+              ;; makes our behavior a superset of the ECMA
+              ;; numeric grammar.  We might not always be so
+              ;; permissive, so we warn about it.
+              (when (and (eq base 8) (>= c ?8))
+                (js2-report-warning "msg.bad.octal.literal"
+                                    (if (eq c ?8) "8" "9"))
+                (setq base 10))
+              (js2-add-to-string c)
+              (setq c (js2-get-char))))
+          (setq is-integer t)
+          (when (and (eq base 10) (memq c '(?. ?e ?E)))
+            (setq is-integer nil)
+            (when (eq c ?.)
+              (loop do
+                    (js2-add-to-string c)
+                    (setq c (js2-get-char))
+                    while (js2-digit-p c)))
+            (when (memq c '(?e ?E))
+              (js2-add-to-string c)
+              (setq c (js2-get-char))
+              (when (memq c '(?+ ?-))
+                (js2-add-to-string c)
+                (setq c (js2-get-char)))
+              (unless (js2-digit-p c)
+                (js2-report-scan-error "msg.missing.exponent" t))
+              (loop do
+                    (js2-add-to-string c)
+                    (setq c (js2-get-char))
+                    while (js2-digit-p c))))
+          (js2-unget-char)
+          (setq js2-ts-string (js2-get-string-from-buffer)
+                js2-ts-number
+                (if (and (eq base 10) (not is-integer))
+                    (string-to-number js2-ts-string)
+                  ;; TODO:  call runtime number-parser.  Some of it is in
+                  ;; js2-util.el, but I need to port 
ScriptRuntime.stringToNumber.
+                  (string-to-number js2-ts-string)))
+          (throw 'return js2-NUMBER))
+        ;; is it a string?
+        (when (memq c '(?\" ?\'))
+          ;; We attempt to accumulate a string the fast way, by
+          ;; building it directly out of the reader.  But if there
+          ;; are any escaped characters in the string, we revert to
+          ;; building it out of a string buffer.
+          (setq quote-char c
+                js2-ts-string-buffer nil
+                c (js2-get-char))
+          (catch 'break
+            (while (/= c quote-char)
+              (catch 'continue
+                (when (or (eq c ?\n) (eq c js2-EOF_CHAR))
+                  (js2-unget-char)
+                  (setq js2-token-end js2-ts-cursor)
+                  (js2-report-error "msg.unterminated.string.lit")
+                  (throw 'return js2-STRING))
+                (when (eq c ?\\)
+                  ;; We've hit an escaped character
+                  (setq c (js2-get-char))
+                  (case c
+                    (?b (setq c ?\b))
+                    (?f (setq c ?\f))
+                    (?n (setq c ?\n))
+                    (?r (setq c ?\r))
+                    (?t (setq c ?\t))
+                    (?v (setq c ?\v))
+                    (?u
+                     (setq c1 (js2-read-unicode-escape))
+                     (if js2-parse-ide-mode
+                         (if c1
+                             (progn
+                               ;; just copy the string in IDE-mode
+                               (js2-add-to-string ?\\)
+                               (js2-add-to-string ?u)
+                               (dotimes (i 3)
+                                 (js2-add-to-string (js2-get-char)))
+                               (setq c (js2-get-char))) ; added at end of loop
+                           ;; flag it as an invalid escape
+                           (js2-report-warning "msg.invalid.escape"
+                                               nil (- js2-ts-cursor 2) 6))
+                       ;; Get 4 hex digits; if the u escape is not
+                       ;; followed by 4 hex digits, use 'u' + the
+                       ;; literal character sequence that follows.
+                       (js2-add-to-string ?u)
+                       (setq escape-val 0)
+                       (dotimes (i 4)
+                         (setq c (js2-get-char)
+                               escape-val (js2-x-digit-to-int c escape-val))
+                         (if (minusp escape-val)
+                             (throw 'continue nil))
+                         (js2-add-to-string c))
+                       ;; prepare for replace of stored 'u' sequence by escape 
value
+                       (setq js2-ts-string-buffer (nthcdr 5 
js2-ts-string-buffer)
+                             c escape-val)))
+                    (?x
+                     ;; Get 2 hex digits, defaulting to 'x'+literal
+                     ;; sequence, as above.
+                     (setq c (js2-get-char)
+                           escape-val (js2-x-digit-to-int c 0))
+                     (if (minusp escape-val)
+                         (progn
+                           (js2-add-to-string ?x)
+                           (throw 'continue nil))
+                       (setq c1 c
+                             c (js2-get-char)
+                             escape-val (js2-x-digit-to-int c escape-val))
+                       (if (minusp escape-val)
+                           (progn
+                             (js2-add-to-string ?x)
+                             (js2-add-to-string c1)
+                             (throw 'continue nil))
+                         ;; got 2 hex digits
+                         (setq c escape-val))))
+                    (?\n
+                     ;; Remove line terminator after escape to follow
+                     ;; SpiderMonkey and C/C++
+                     (setq c (js2-get-char))
+                     (throw 'continue nil))
+                    (t
+                     (when (and (<= ?0 c) (< c ?8))
+                       (setq val (- c ?0)
+                             c (js2-get-char))
+                       (when (and (<= ?0 c) (< c ?8))
+                         (setq val (- (+ (* 8 val) c) ?0)
+                               c (js2-get-char))
+                         (when (and (<= ?0 c)
+                                    (< c ?8)
+                                    (< val #o37))
+                           ;; c is 3rd char of octal sequence only
+                           ;; if the resulting val <= 0377
+                           (setq val (- (+ (* 8 val) c) ?0)
+                                 c (js2-get-char))))
+                       (js2-unget-char)
+                       (setq c val)))))
+                (js2-add-to-string c)
+                (setq c (js2-get-char)))))
+          (setq js2-ts-string (js2-get-string-from-buffer))
+          (throw 'return js2-STRING))
+        (case c
+          (?\;
+           (throw 'return js2-SEMI))
+          (?\[
+           (throw 'return js2-LB))
+          (?\]
+           (throw 'return js2-RB))
+          (?{
+           (throw 'return js2-LC))
+          (?}
+           (throw 'return js2-RC))
+          (?\(
+           (throw 'return js2-LP))
+          (?\)
+           (throw 'return js2-RP))
+          (?,
+           (throw 'return js2-COMMA))
+          (??
+           (throw 'return js2-HOOK))
+          (?:
+           (if (js2-match-char ?:)
+               (js2-ts-return js2-COLONCOLON)
+             (throw 'return js2-COLON)))
+          (?.
+           (if (js2-match-char ?.)
+               (js2-ts-return js2-DOTDOT)
+             (if (js2-match-char ?\()
+                 (js2-ts-return js2-DOTQUERY)
+               (throw 'return js2-DOT))))
+          (?|
+           (if (js2-match-char ?|)
+               (throw 'return js2-OR)
+             (if (js2-match-char ?=)
+                 (js2-ts-return js2-ASSIGN_BITOR)
+               (throw 'return js2-BITOR))))
+          (?^
+           (if (js2-match-char ?=)
+               (js2-ts-return js2-ASSIGN_BITOR)
+             (throw 'return js2-BITXOR)))
+          (?&
+           (if (js2-match-char ?&)
+               (throw 'return js2-AND)
+             (if (js2-match-char ?=)
+                 (js2-ts-return js2-ASSIGN_BITAND)
+               (throw 'return js2-BITAND))))
+          (?=
+           (if (js2-match-char ?=)
+               (if (js2-match-char ?=)
+                   (js2-ts-return js2-SHEQ)
+                 (throw 'return js2-EQ))
+             (throw 'return js2-ASSIGN)))
+          (?!
+           (if (js2-match-char ?=)
+               (if (js2-match-char ?=)
+                   (js2-ts-return js2-SHNE)
+                 (js2-ts-return js2-NE))
+             (throw 'return js2-NOT)))
+          (?<
+           ;; NB:treat HTML begin-comment as comment-till-eol
+           (when (js2-match-char ?!)
+             (when (js2-match-char ?-)
+               (when (js2-match-char ?-)
+                 (js2-skip-line)
+                 (setq js2-ts-comment-type 'html)
+                 (throw 'return js2-COMMENT)))
+             (js2-unget-char))
+           (if (js2-match-char ?<)
+               (if (js2-match-char ?=)
+                   (js2-ts-return js2-ASSIGN_LSH)
+                 (js2-ts-return js2-LSH))
+             (if (js2-match-char ?=)
+                 (js2-ts-return js2-LE)
+               (throw 'return js2-LT))))
+          (?>
+           (if (js2-match-char ?>)
+               (if (js2-match-char ?>)
+                   (if (js2-match-char ?=)
+                       (js2-ts-return js2-ASSIGN_URSH)
+                     (js2-ts-return js2-URSH))
+                 (if (js2-match-char ?=)
+                     (js2-ts-return js2-ASSIGN_RSH)
+                   (js2-ts-return js2-RSH)))
+             (if (js2-match-char ?=)
+                 (js2-ts-return js2-GE)
+               (throw 'return js2-GT))))
+          (?*
+           (if (js2-match-char ?=)
+               (js2-ts-return js2-ASSIGN_MUL)
+             (throw 'return js2-MUL)))
+          (?/
+           ;; is it a // comment?
+           (when (js2-match-char ?/)
+             (setq js2-token-beg (- js2-ts-cursor 2))
+             (js2-skip-line)
+             (setq js2-ts-comment-type 'line)
+             ;; include newline so highlighting goes to end of window
+             (incf js2-token-end)
+             (throw 'return js2-COMMENT))
+           ;; is it a /* comment?
+           (when (js2-match-char ?*)
+             (setq look-for-slash nil
+                   js2-token-beg (- js2-ts-cursor 2)
+                   js2-ts-comment-type
+                   (if (js2-match-char ?*)
+                       (progn
+                         (setq look-for-slash t)
+                         'jsdoc)
+                     'block))
+             (while t
+               (setq c (js2-get-char))
+               (cond
+                ((eq c js2-EOF_CHAR)
+                 (setq js2-token-end (1- js2-ts-cursor))
+                 (js2-report-error "msg.unterminated.comment")
+                 (throw 'return js2-COMMENT))
+                ((eq c ?*)
+                 (setq look-for-slash t))
+                ((eq c ?/)
+                 (if look-for-slash
+                   (js2-ts-return js2-COMMENT)))
+                (t
+                 (setq look-for-slash nil
+                       js2-token-end js2-ts-cursor)))))
+           (if (js2-match-char ?=)
+               (js2-ts-return js2-ASSIGN_DIV)
+             (throw 'return js2-DIV)))
+           (?#
+            (when js2-skip-preprocessor-directives
+              (js2-skip-line)
+              (setq js2-ts-comment-type 'preprocessor
+                    js2-token-end js2-ts-cursor)
+              (throw 'return js2-COMMENT))
+            (throw 'return js2-ERROR))
+          (?%
+           (if (js2-match-char ?=)
+               (js2-ts-return js2-ASSIGN_MOD)
+             (throw 'return js2-MOD)))
+          (?~
+           (throw 'return js2-BITNOT))
+          (?+
+           (if (js2-match-char ?=)
+               (js2-ts-return js2-ASSIGN_ADD)
+             (if (js2-match-char ?+)
+                 (js2-ts-return js2-INC)
+               (throw 'return js2-ADD))))
+          (?-
+           (cond
+            ((js2-match-char ?=)
+             (setq c js2-ASSIGN_SUB))
+            ((js2-match-char ?-)
+             (unless js2-ts-dirty-line
+               ;; treat HTML end-comment after possible whitespace
+               ;; after line start as comment-until-eol
+               (when (js2-match-char ?>)
+                 (js2-skip-line)
+                 (setq js2-ts-comment-type 'html)
+                 (throw 'return js2-COMMENT)))
+             (setq c js2-DEC))
+            (t
+             (setq c js2-SUB)))
+           (setq js2-ts-dirty-line t)
+           (js2-ts-return c))
+          (otherwise
+           (js2-report-scan-error "msg.illegal.character")))))))
+
+(defun js2-read-regexp (start-token)
+  "Called by parser when it gets / or /= in literal context."
+  (let (c
+        err
+        in-class  ; inside a '[' .. ']' character-class
+        flags
+        (continue t))
+    (setq js2-token-beg js2-ts-cursor
+          js2-ts-string-buffer nil
+          js2-ts-regexp-flags nil)
+    (if (eq start-token js2-ASSIGN_DIV)
+        ;; mis-scanned /=
+        (js2-add-to-string ?=)
+      (if (not (eq start-token js2-DIV))
+          (error "failed assertion")))
+    (while (and (not err)
+                (or (/= (setq c (js2-get-char)) ?/)
+                    in-class))
+      (cond
+       ((or (= c ?\n)
+            (= c js2-EOF_CHAR))
+        (setq js2-token-end (1- js2-ts-cursor)
+              err t
+              js2-ts-string (js2-collect-string js2-ts-string-buffer))
+        (js2-report-error "msg.unterminated.re.lit"))
+       (t (cond
+           ((= c ?\\)
+            (js2-add-to-string c)
+            (setq c (js2-get-char)))
+           ((= c ?\[)
+            (setq in-class t))
+           ((= c ?\])
+            (setq in-class nil)))
+          (js2-add-to-string c))))
+    (unless err
+      (while continue
+        (cond
+         ((js2-match-char ?g)
+          (push ?g flags))
+         ((js2-match-char ?i)
+          (push ?i flags))
+         ((js2-match-char ?m)
+          (push ?m flags))
+         (t
+          (setq continue nil))))
+      (if (js2-alpha-p (js2-peek-char))
+          (js2-report-scan-error "msg.invalid.re.flag" t
+                                 js2-ts-cursor 1))
+      (setq js2-ts-string (js2-collect-string js2-ts-string-buffer)
+            js2-ts-regexp-flags (js2-collect-string flags)
+            js2-token-end js2-ts-cursor)
+      ;; tell `parse-partial-sexp' to ignore this range of chars
+      (put-text-property js2-token-beg js2-token-end 'syntax-class '(2)))))
+
+(defun js2-get-first-xml-token ()
+  (setq js2-ts-xml-open-tags-count 0
+        js2-ts-is-xml-attribute nil
+        js2-ts-xml-is-tag-content nil)
+  (js2-unget-char)
+  (js2-get-next-xml-token))
+
+(defsubst js2-xml-discard-string ()
+  "Throw away the string in progress and flag an XML parse error."
+  (setq js2-ts-string-buffer nil
+        js2-ts-string nil)
+  (js2-report-scan-error "msg.XML.bad.form" t))
+
+(defun js2-get-next-xml-token ()
+  (setq js2-ts-string-buffer nil  ; for recording the XML
+        js2-token-beg js2-ts-cursor)
+  (let (c result)
+    (setq result
+          (catch 'return
+            (while t
+              (setq c (js2-get-char))
+              (cond
+               ((= c js2-EOF_CHAR)
+                (throw 'return js2-ERROR))
+               (js2-ts-xml-is-tag-content
+                (case c
+                  (?>
+                   (js2-add-to-string c)
+                   (setq js2-ts-xml-is-tag-content nil
+                         js2-ts-is-xml-attribute nil))
+                  (?/
+                   (js2-add-to-string c)
+                   (when (eq ?> (js2-peek-char))
+                     (setq c (js2-get-char))
+                     (js2-add-to-string c)
+                     (setq js2-ts-xml-is-tag-content nil)
+                     (decf js2-ts-xml-open-tags-count)))
+                  (?{
+                   (js2-unget-char)
+                   (setq js2-ts-string (js2-get-string-from-buffer))
+                   (throw 'return js2-XML))
+                  ((?\' ?\")
+                   (js2-add-to-string c)
+                   (unless (js2-read-quoted-string c)
+                     (throw 'return js2-ERROR)))
+                  (?=
+                   (js2-add-to-string c)
+                   (setq js2-ts-is-xml-attribute t))
+                  ((? ?\t ?\r ?\n)
+                   (js2-add-to-string c))
+                  (t
+                   (js2-add-to-string c)
+                   (setq js2-ts-is-xml-attribute nil)))
+                (when (and (not js2-ts-xml-is-tag-content)
+                           (zerop js2-ts-xml-open-tags-count))
+                  (setq js2-ts-string (js2-get-string-from-buffer))
+                  (throw 'return js2-XMLEND)))
+               (t
+                ;; else not tag content
+                (case c
+                  (?<
+                   (js2-add-to-string c)
+                   (setq c (js2-peek-char))
+                   (case c
+                     (?!
+                      (setq c (js2-get-char)) ;; skip !
+                      (js2-add-to-string c)
+                      (setq c (js2-peek-char))
+                      (case c
+                        (?-
+                         (setq c (js2-get-char)) ;; skip -
+                         (js2-add-to-string c)
+                         (if (eq c ?-)
+                             (progn
+                               (js2-add-to-string c)
+                               (unless (js2-read-xml-comment)
+                                 (throw 'return js2-ERROR)))
+                           (js2-xml-discard-string)
+                           (throw 'return js2-ERROR)))
+                        (?\[
+                         (setq c (js2-get-char)) ;; skip [
+                         (js2-add-to-string c)
+                         (if (and (= (js2-get-char) ?C)
+                                  (= (js2-get-char) ?D)
+                                  (= (js2-get-char) ?A)
+                                  (= (js2-get-char) ?T)
+                                  (= (js2-get-char) ?A)
+                                  (= (js2-get-char) ?\[))
+                             (progn
+                               (js2-add-to-string ?C)
+                               (js2-add-to-string ?D)
+                               (js2-add-to-string ?A)
+                               (js2-add-to-string ?T)
+                               (js2-add-to-string ?A)
+                               (js2-add-to-string ?\[)
+                               (unless (js2-read-cdata)
+                                 (throw 'return js2-ERROR)))
+                           (js2-xml-discard-string)
+                           (throw 'return js2-ERROR)))
+                        (t
+                         (unless (js2-read-entity)
+                           (throw 'return js2-ERROR)))))
+                     (??
+                      (setq c (js2-get-char)) ;; skip ?
+                      (js2-add-to-string c)
+                      (unless (js2-read-PI)
+                        (throw 'return js2-ERROR)))
+                     (?/
+                      ;; end tag
+                      (setq c (js2-get-char)) ;; skip /
+                      (js2-add-to-string c)
+                      (when (zerop js2-ts-xml-open-tags-count)
+                        (js2-xml-discard-string)
+                        (throw 'return js2-ERROR))
+                      (setq js2-ts-xml-is-tag-content t)
+                      (decf js2-ts-xml-open-tags-count))
+                     (t
+                      ;; start tag
+                      (setq js2-ts-xml-is-tag-content t)
+                      (incf js2-ts-xml-open-tags-count))))
+                  (?{
+                   (js2-unget-char)
+                   (setq js2-ts-string (js2-get-string-from-buffer))
+                   (throw 'return js2-XML))
+                  (t
+                   (js2-add-to-string c))))))))
+    (setq js2-token-end js2-ts-cursor)
+    result))
+
+(defun js2-read-quoted-string (quote)
+  (let (c)
+    (catch 'return
+      (while (/= (setq c (js2-get-char)) js2-EOF_CHAR)
+        (js2-add-to-string c)
+        (if (eq c quote)
+            (throw 'return t)))
+      (js2-xml-discard-string)  ;; throw away string in progress
+      nil)))
+
+(defun js2-read-xml-comment ()
+  (let ((c (js2-get-char)))
+    (catch 'return
+      (while (/= c js2-EOF_CHAR)
+        (catch 'continue
+          (js2-add-to-string c)
+          (when (and (eq c ?-) (eq ?- (js2-peek-char)))
+            (setq c (js2-get-char))
+            (js2-add-to-string c)
+            (if (eq (js2-peek-char) ?>)
+                (progn
+                  (setq c (js2-get-char)) ;; skip >
+                  (js2-add-to-string c)
+                  (throw 'return t))
+              (throw 'continue nil)))
+          (setq c (js2-get-char))))
+      (js2-xml-discard-string)
+      nil)))
+
+(defun js2-read-cdata ()
+  (let ((c (js2-get-char)))
+    (catch 'return
+      (while (/= c js2-EOF_CHAR)
+        (catch 'continue
+          (js2-add-to-string c)
+          (when (and (eq c ?\]) (eq (js2-peek-char) ?\]))
+            (setq c (js2-get-char))
+            (js2-add-to-string c)
+            (if (eq (js2-peek-char) ?>)
+                (progn
+                  (setq c (js2-get-char)) ;; Skip >
+                  (js2-add-to-string c)
+                  (throw 'return t))
+              (throw 'continue nil)))
+          (setq c (js2-get-char))))
+      (js2-xml-discard-string)
+      nil)))
+
+(defun js2-read-entity ()
+  (let ((decl-tags 1)
+        c)
+    (catch 'return
+      (while (/= js2-EOF_CHAR (setq c (js2-get-char)))
+        (js2-add-to-string c)
+        (case c
+          (?<
+           (incf decl-tags))
+          (?>
+           (decf decl-tags)
+           (if (zerop decl-tags)
+               (throw 'return t)))))
+      (js2-xml-discard-string)
+      nil)))
+
+(defun js2-read-PI ()
+  "Scan an XML processing instruction."
+  (let (c)
+    (catch 'return
+      (while (/= js2-EOF_CHAR (setq c (js2-get-char)))
+        (js2-add-to-string c)
+        (when (and (eq c ??) (eq (js2-peek-char) ?>))
+          (setq c (js2-get-char))  ;; Skip >
+          (js2-add-to-string c)
+          (throw 'return t)))
+      (js2-xml-discard-string)
+      nil)))
+
+(defun js2-scanner-get-line ()
+  "Return the text of the current scan line."
+  (buffer-substring (point-at-bol) (point-at-eol)))
+
+;;; Highlighting
+
+(defsubst js2-set-face (beg end face &optional record)
+  "Fontify a region.  If RECORD is non-nil, record for later."
+  (when (plusp js2-highlight-level)
+    (setq beg (min (point-max) beg)
+          beg (max (point-min) beg)
+          end (min (point-max) end)
+          end (max (point-min) end))
+    (if record
+        (push (list beg end face) js2-mode-fontifications)
+      (put-text-property beg end 'face face))))
+
+(defsubst js2-set-kid-face (pos kid len face)
+  "Set-face on a child node.
+POS is absolute buffer position of parent.
+KID is the child node.
+LEN is the length to fontify.
+FACE is the face to fontify with."
+  (js2-set-face (+ pos (js2-node-pos kid))
+                (+ pos (js2-node-pos kid) (js2-node-len kid))
+                face))
+
+(defsubst js2-fontify-kwd (start length)
+  (js2-set-face start (+ start length) 'font-lock-keyword-face))
+
+(defsubst js2-clear-face (beg end)
+  (remove-text-properties beg end '(face nil
+                                    help-echo nil
+                                    point-entered nil
+                                    c-in-sws nil)))
+
+(defsubst js2-record-text-property (beg end prop value)
+  "Record a text property to set when parsing finishes."
+  (push (list beg end prop value) js2-mode-deferred-properties))
+
+(defconst js2-ecma-global-props
+  (concat "^"
+          (regexp-opt
+           '("Infinity" "NaN" "undefined" "arguments") t)
+          "$")
+  "Value properties of the Ecma-262 Global Object.
+Shown at or above `js2-highlight-level' 2.")
+
+;; might want to add the name "arguments" to this list?
+(defconst js2-ecma-object-props
+  (concat "^"
+          (regexp-opt
+           '("prototype" "__proto__" "__parent__") t)
+          "$")
+  "Value properties of the Ecma-262 Object constructor.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-global-funcs
+  (concat
+   "^"
+   (regexp-opt
+    '("decodeURI" "decodeURIComponent" "encodeURI" "encodeURIComponent"
+      "eval" "isFinite" "isNaN" "parseFloat" "parseInt") t)
+   "$")
+  "Function properties of the Ecma-262 Global object.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-number-props
+  (concat "^"
+          (regexp-opt '("MAX_VALUE" "MIN_VALUE" "NaN"
+                        "NEGATIVE_INFINITY"
+                        "POSITIVE_INFINITY") t)
+          "$")
+  "Properties of the Ecma-262 Number constructor.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-date-props "^\\(parse\\|UTC\\)$"
+  "Properties of the Ecma-262 Date constructor.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-math-props
+  (concat "^"
+          (regexp-opt
+           '("E" "LN10" "LN2" "LOG2E" "LOG10E" "PI" "SQRT1_2" "SQRT2")
+           t)
+          "$")
+  "Properties of the Ecma-262 Math object.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-math-funcs
+  (concat "^"
+          (regexp-opt
+           '("abs" "acos" "asin" "atan" "atan2" "ceil" "cos" "exp" "floor"
+             "log" "max" "min" "pow" "random" "round" "sin" "sqrt" "tan") t)
+          "$")
+  "Function properties of the Ecma-262 Math object.
+Shown at or above `js2-highlight-level' 2.")
+
+(defconst js2-ecma-function-props
+  (concat
+   "^"
+   (regexp-opt
+    '(;; properties of the Object prototype object
+      "hasOwnProperty" "isPrototypeOf" "propertyIsEnumerable"
+      "toLocaleString" "toString" "valueOf"
+      ;; properties of the Function prototype object
+      "apply" "call"
+      ;; properties of the Array prototype object
+      "concat" "join" "pop" "push" "reverse" "shift" "slice" "sort"
+      "splice" "unshift"
+      ;; properties of the String prototype object
+      "charAt" "charCodeAt" "fromCharCode" "indexOf" "lastIndexOf"
+      "localeCompare" "match" "replace" "search" "split" "substring"
+      "toLocaleLowerCase" "toLocaleUpperCase" "toLowerCase"
+      "toUpperCase"
+      ;; properties of the Number prototype object
+      "toExponential" "toFixed" "toPrecision"
+      ;; properties of the Date prototype object
+      "getDate" "getDay" "getFullYear" "getHours" "getMilliseconds"
+      "getMinutes" "getMonth" "getSeconds" "getTime"
+      "getTimezoneOffset" "getUTCDate" "getUTCDay" "getUTCFullYear"
+      "getUTCHours" "getUTCMilliseconds" "getUTCMinutes" "getUTCMonth"
+      "getUTCSeconds" "setDate" "setFullYear" "setHours"
+      "setMilliseconds" "setMinutes" "setMonth" "setSeconds" "setTime"
+      "setUTCDate" "setUTCFullYear" "setUTCHours" "setUTCMilliseconds"
+      "setUTCMinutes" "setUTCMonth" "setUTCSeconds" "toDateString"
+      "toLocaleDateString" "toLocaleString" "toLocaleTimeString"
+      "toTimeString" "toUTCString"
+      ;; properties of the RegExp prototype object
+      "exec" "test"
+      ;; SpiderMonkey/Rhino extensions, versions 1.5+
+      "toSource" "__defineGetter__" "__defineSetter__"
+      "__lookupGetter__" "__lookupSetter__" "__noSuchMethod__"
+      "every" "filter" "forEach" "lastIndexOf" "map" "some")
+    t)
+   "$")
+  "Built-in functions defined by Ecma-262 and SpiderMonkey extensions.
+Shown at or above `js2-highlight-level' 3.")
+
+(defsubst js2-parse-highlight-prop-get (parent target prop call-p)
+  (let ((target-name (and target
+                          (js2-name-node-p target)
+                          (js2-name-node-name target)))
+        (prop-name (if prop (js2-name-node-name prop)))
+        (level1 (>= js2-highlight-level 1))
+        (level2 (>= js2-highlight-level 2))
+        (level3 (>= js2-highlight-level 3))
+        pos
+        face)
+    (when level2
+      (if call-p
+          (cond
+           ((and target prop)
+            (cond
+             ((and level3 (string-match js2-ecma-function-props prop-name))
+              (setq face 'font-lock-builtin-face))
+             ((and target-name prop)
+              (cond
+               ((string= target-name "Date")
+                (if (string-match js2-ecma-date-props prop-name)
+                    (setq face 'font-lock-builtin-face)))
+               ((string= target-name "Math")
+                (if (string-match js2-ecma-math-funcs prop-name)
+                    (setq face 'font-lock-builtin-face)))))))
+           (prop
+            (if (string-match js2-ecma-global-funcs prop-name)
+                (setq face 'font-lock-builtin-face))))
+        (cond
+         ((and target prop)
+          (cond
+           ((string= target-name "Number")
+            (if (string-match js2-ecma-number-props prop-name)
+                (setq face 'font-lock-constant-face)))
+           ((string= target-name "Math")
+            (if (string-match js2-ecma-math-props prop-name)
+                (setq face 'font-lock-constant-face)))))
+         (prop
+          (if (string-match js2-ecma-object-props prop-name)
+              (setq face 'font-lock-constant-face)))))
+      (when face
+        (js2-set-face (setq pos (+ (js2-node-pos parent) ; absolute
+                                   (js2-node-pos prop))) ; relative
+                      (+ pos (js2-node-len prop))
+                      face)))))
+
+(defun js2-parse-highlight-member-expr-node (node)
+  "Perform syntax highlighting of EcmaScript built-in properties.
+The variable `js2-highlight-level' governs this highighting."
+  (let (face target prop name pos end parent call-p callee)
+    (cond
+     ;; case 1:  simple name, e.g. foo
+     ((js2-name-node-p node)
+      (setq name (js2-name-node-name node))
+      ;; possible for name to be nil in rare cases - saw it when
+      ;; running js2-mode on an elisp buffer.  Might as well try to
+      ;; make it so js2-mode never barfs.
+      (when name
+        (setq face (if (string-match js2-ecma-global-props name)
+                       'font-lock-constant-face))
+        (when face
+          (setq pos (js2-node-pos node)
+                end (+ pos (js2-node-len node)))
+          (js2-set-face pos end face))))
+     ;; case 2:  property access or function call
+     ((or (js2-prop-get-node-p node)
+          ;; highlight function call if expr is a prop-get node
+          ;; or a plain name (i.e. unqualified function call)
+          (and (setq call-p (js2-call-node-p node))
+               (setq callee (js2-call-node-target node)) ; separate setq!
+               (or (js2-prop-get-node-p callee)
+                   (js2-name-node-p callee))))
+      (setq parent node
+            node (if call-p callee node))
+      (if (and call-p (js2-name-node-p callee))
+          (setq prop callee)
+        (setq target (js2-prop-get-node-left node)
+              prop (js2-prop-get-node-right node)))
+      (cond
+       ((js2-name-node-p target)
+        (if (js2-name-node-p prop)
+            ;; case 2a:  simple target, simple prop name, e.g. foo.bar
+            (js2-parse-highlight-prop-get parent target prop call-p)
+          ;; case 2b:  simple target, complex name, e.g. foo.x[y]
+          (js2-parse-highlight-prop-get parent target nil call-p)))
+       ((js2-name-node-p prop)
+        ;; case 2c:  complex target, simple name, e.g. x[y].bar
+        (js2-parse-highlight-prop-get parent target prop call-p)))))))
+
+(defun js2-parse-highlight-member-expr-fn-name (expr)
+  "Highlight the `baz' in function foo.bar.baz(args) {...}.
+This is experimental Rhino syntax.  EXPR is the foo.bar.baz member expr.
+We currently only handle the case where the last component is a prop-get
+of a simple name.  Called before EXPR has a parent node."
+  (let (pos
+        (name (and (js2-prop-get-node-p expr)
+                   (js2-prop-get-node-right expr))))
+    (when (js2-name-node-p name)
+      (js2-set-face (setq pos (+ (js2-node-pos expr)  ; parent is absolute
+                                 (js2-node-pos name)))
+                    (+ pos (js2-node-len name))
+                    'font-lock-function-name-face
+                    'record))))
+
+;; source:  http://jsdoc.sourceforge.net/
+;; Note - this syntax is for Google's enhanced jsdoc parser that
+;; allows type specifications, and needs work before entering the wild.
+
+(defconst js2-jsdoc-param-tag-regexp
+  (concat "^\\s-*\\*+\\s-*\\(@"
+          "\\(?:param\\|argument\\)"
+          "\\)"
+          "\\s-*\\({[^}]+}\\)?"         ; optional type
+          "\\s-*\\([a-zA-Z0-9_$]+\\)?"  ; name
+          "\\>")
+  "Matches jsdoc tags with optional type and optional param name.")
+
+(defconst js2-jsdoc-typed-tag-regexp
+  (concat "^\\s-*\\*+\\s-*\\(@\\(?:"
+          (regexp-opt
+           '("enum"
+             "extends"
+             "field"
+             "id"
+             "implements"
+             "lends"
+             "mods"
+             "requires"
+             "return"
+             "returns"
+             "throw"
+             "throws"))
+          "\\)\\)\\s-*\\({[^}]+}\\)?")
+  "Matches jsdoc tags with optional type.")
+
+(defconst js2-jsdoc-arg-tag-regexp
+  (concat "^\\s-*\\*+\\s-*\\(@\\(?:"
+          (regexp-opt
+           '("alias"
+             "augments"
+             "borrows"
+             "bug"
+             "base"
+             "config"
+             "default"
+             "define"
+             "exception"
+             "function"
+             "member"
+             "memberOf"
+             "name"
+             "namespace"
+             "property"
+             "since"
+             "suppress"
+             "this"
+             "throws"
+             "type"
+             "version"))
+          "\\)\\)\\s-+\\([^ \t]+\\)")
+  "Matches jsdoc tags with a single argument.")
+
+(defconst js2-jsdoc-empty-tag-regexp
+  (concat "^\\s-*\\*+\\s-*\\(@\\(?:"
+          (regexp-opt
+           '("addon"
+             "author"
+             "class"
+             "const"
+             "constant"
+             "constructor"
+             "constructs"
+             "deprecated"
+             "desc"
+             "description"
+             "event"
+             "example"
+             "exec"
+             "export"
+             "fileoverview"
+             "final"
+             "function"
+             "hidden"
+             "ignore"
+             "implicitCast"
+             "inheritDoc"
+             "inner"
+             "interface"
+             "license"
+             "noalias"
+             "noshadow"
+             "notypecheck"
+             "override"
+             "owner"
+             "preserve"
+             "preserveTry"
+             "private"
+             "protected"
+             "public"
+             "static"
+             "supported"
+             ))
+          "\\)\\)\\s-*")
+  "Matches empty jsdoc tags.")
+
+(defconst js2-jsdoc-link-tag-regexp
+  "{\\(@\\(?:link\\|code\\)\\)\\s-+\\([^#}\n]+\\)\\(#.+\\)?}"
+  "Matches a jsdoc link or code tag.")
+
+(defconst js2-jsdoc-see-tag-regexp
+  "^\\s-*\\*+\\s-*\\(@see\\)\\s-+\\([^#}\n]+\\)\\(#.+\\)?"
+  "Matches a jsdoc @see tag.")
+
+(defconst js2-jsdoc-html-tag-regexp
+  "\\(</?\\)\\([a-zA-Z]+\\)\\s-*\\(/?>\\)"
+  "Matches a simple (no attributes) html start- or end-tag.")
+
+(defsubst js2-jsdoc-highlight-helper ()
+  (js2-set-face (match-beginning 1)
+                (match-end 1)
+                'js2-jsdoc-tag-face)
+  (if (match-beginning 2)
+      (if (save-excursion
+            (goto-char (match-beginning 2))
+            (= (char-after) ?{))
+          (js2-set-face (1+ (match-beginning 2))
+                        (1- (match-end 2))
+                        'js2-jsdoc-type-face)
+        (js2-set-face (match-beginning 2)
+                      (match-end 2)
+                      'js2-jsdoc-value-face)))
+  (if (match-beginning 3)
+      (js2-set-face (match-beginning 3)
+                    (match-end 3)
+                    'js2-jsdoc-value-face)))
+
+(defun js2-highlight-jsdoc (ast)
+  "Highlight doc comment tags."
+  (let ((comments (js2-ast-root-comments ast))
+        beg end)
+    (save-excursion
+      (dolist (node comments)
+        (when (eq (js2-comment-node-format node) 'jsdoc)
+          (setq beg (js2-node-abs-pos node)
+                end (+ beg (js2-node-len node)))
+          (save-restriction
+            (narrow-to-region beg end)
+            (dolist (re (list js2-jsdoc-param-tag-regexp
+                              js2-jsdoc-typed-tag-regexp
+                              js2-jsdoc-arg-tag-regexp
+                              js2-jsdoc-link-tag-regexp
+                              js2-jsdoc-see-tag-regexp
+                              js2-jsdoc-empty-tag-regexp))
+              (goto-char beg)
+              (while (re-search-forward re nil t)
+                (js2-jsdoc-highlight-helper)))
+            ;; simple highlighting for html tags
+            (goto-char beg)
+            (while (re-search-forward js2-jsdoc-html-tag-regexp nil t)
+              (js2-set-face (match-beginning 1)
+                            (match-end 1)
+                            'js2-jsdoc-html-tag-delimiter-face)
+              (js2-set-face (match-beginning 2)
+                            (match-end 2)
+                            'js2-jsdoc-html-tag-name-face)
+              (js2-set-face (match-beginning 3)
+                            (match-end 3)
+                            'js2-jsdoc-html-tag-delimiter-face))))))))
+
+(defun js2-highlight-assign-targets (node left right)
+  "Highlight function properties and external variables."
+  (let (leftpos end name)
+    ;; highlight vars and props assigned function values
+    (when (js2-function-node-p right)
+      (cond
+       ;; var foo = function() {...}
+       ((js2-name-node-p left)
+        (setq name left))
+       ;; foo.bar.baz = function() {...}
+       ((and (js2-prop-get-node-p left)
+             (js2-name-node-p (js2-prop-get-node-right left)))
+        (setq name (js2-prop-get-node-right left))))
+      (when name
+        (js2-set-face (setq leftpos (js2-node-abs-pos name))
+                      (+ leftpos (js2-node-len name))
+                      'font-lock-function-name-face
+                      'record)))
+    ;; save variable assignments so we can check for undeclared later
+    ;; (can't do it here since var decls can come at end of script)
+    (when (and js2-highlight-external-variables
+               (setq name (js2-member-expr-leftmost-name left)))
+      (push (list name js2-current-scope
+                  (setq leftpos (js2-node-abs-pos name))
+                  (setq end (+ leftpos (js2-node-len name))))
+            js2-recorded-assignments))))
+
+(defun js2-highlight-undeclared-vars ()
+  "After entire parse is finished, look for undeclared variable assignments.
+We have to wait until entire buffer is parsed, since JavaScript permits var
+decls to occur after they're used.
+
+If any undeclared var name is in `js2-externs' or `js2-additional-externs',
+it is considered declared."
+  (let (name)
+    (dolist (entry js2-recorded-assignments)
+      (destructuring-bind (name-node scope pos end) entry
+        (setq name (js2-name-node-name name-node))
+        (unless (or (member name js2-global-externs)
+                    (member name js2-default-externs)
+                    (member name js2-additional-externs)
+                    (js2-get-defining-scope scope name))
+          (js2-set-face pos end 'js2-external-variable-face 'record)
+          (js2-record-text-property pos end 'help-echo "Undeclared variable")
+          (js2-record-text-property pos end 'point-entered #'js2-echo-help))))
+    (setq js2-recorded-assignments nil)))
+
+;;; IMenu support
+
+;; We currently only support imenu, but eventually should support speedbar and
+;; possibly other browsing mechanisms.
+
+;; The basic strategy is to identify function assignment targets of the form
+;; `foo.bar.baz', convert them to (list foo bar baz <position>), and push the
+;; list into `js2-imenu-recorder'.  The lists are merged into a trie-like tree
+;; for imenu after parsing is finished.
+
+;; A `foo.bar.baz' assignment target may be expressed in many ways in
+;; JavaScript, and the general problem is undecidable.  However, several forms
+;; are readily recognizable at parse-time; the forms we attempt to recognize
+;; include:
+
+;;  function foo()  -- function declaration
+;;  foo = function()  -- function expression assigned to variable
+;;  foo.bar.baz = function()  -- function expr assigned to nested property-get
+;;  foo = {bar: function()}  -- fun prop in object literal assigned to var
+;;  foo = {bar: {baz: function()}} -- inside nested object literal
+;;  foo.bar = {baz: function()}} -- obj lit assigned to nested prop get
+;;  a.b = {c: {d: function()}} -- nested obj lit assigned to nested prop get
+;;  foo = {get bar() {...}}  -- getter/setter in obj literal
+;;  function foo() {function bar() {...}}  -- nested function
+;;  foo['a'] = function()  -- fun expr assigned to deterministic element-get
+
+;; This list boils down to a few forms that can be combined recursively.
+;; Top-level named function declarations include both the left-hand (name)
+;; and the right-hand (function value) expressions needed to produce an imenu
+;; entry.  The other "right-hand" forms we need to look for are:
+;;  - functions declared as props/getters/setters in object literals
+;;  - nested named function declarations
+;; The "left-hand" expressions that functions can be assigned to include:
+;;  - local/global variables
+;;  - nested property-get expressions like a.b.c.d
+;;  - element gets like foo[10] or foo['bar'] where the index
+;;    expression can be trivially converted to a property name.  They
+;;    effectively then become property gets.
+
+;; All the different definition types are canonicalized into the form
+;; foo.bar.baz = position-of-function-keyword
+
+;; We need to build a trie-like structure for imenu.  As an example,
+;; consider the following JavaScript code:
+
+;; a = function() {...}  // function at position 5
+;; b = function() {...}  // function at position 25
+;; foo = function() {...} // function at position 100
+;; foo.bar = function() {...} // function at position 200
+;; foo.bar.baz = function() {...} // function at position 300
+;; foo.bar.zab = function() {...} // function at position 400
+
+;; During parsing we accumulate an entry for each definition in
+;; the variable `js2-imenu-recorder', like so:
+
+;; '((a 5)
+;;   (b 25)
+;;   (foo 100)
+;;   (foo bar 200)
+;;   (foo bar baz 300)
+;;   (foo bar zab 400))
+
+;; After parsing these entries are merged into this alist-trie:
+
+;; '((a . 1)
+;;   (b . 2)
+;;   (foo (<definition> . 3)
+;;        (bar (<definition> . 6)
+;;             (baz . 100)
+;;             (zab . 200))))
+
+;; Note the wacky need for a <definition> name.  The token can be anything
+;; that isn't a valid JavaScript identifier, because you might make foo
+;; a function and then start setting properties on it that are also functions.
+
+(defsubst js2-prop-node-name (node)
+  "Return the name of a node that may be a property-get/property-name.
+If NODE is not a valid name-node, string-node or integral number-node,
+returns nil.  Otherwise returns the string name/value of the node."
+  (cond
+   ((js2-name-node-p node)
+    (js2-name-node-name node))
+   ((js2-string-node-p node)
+    (js2-string-node-value node))
+   ((and (js2-number-node-p node)
+         (string-match "^[0-9]+$" (js2-number-node-value node)))
+    (js2-number-node-value node))
+   ((js2-this-node-p node)
+    "this")))
+
+(defsubst js2-node-qname-component (node)
+  "Test function:  return the name of this node, if it contributes to a qname.
+Returns nil if the node doesn't contribute."
+  (copy-sequence
+   (or (js2-prop-node-name node)
+       (if (and (js2-function-node-p node)
+                (js2-function-node-name node))
+           (js2-name-node-name (js2-function-node-name node))))))
+
+(defsubst js2-record-function-qname (fn-node qname)
+  "Associate FN-NODE with its QNAME for later lookup.
+This is used in postprocessing the chain list.  When we find a chain
+whose first element is a js2-THIS keyword node, we look up the parent
+function and see (using this map) whether it is the tail of a chain.
+If so, we replace the this-node with a copy of the parent's qname."
+  (unless js2-imenu-function-map
+    (setq js2-imenu-function-map (make-hash-table :test 'eq)))
+  (puthash fn-node qname js2-imenu-function-map))
+
+(defun js2-record-imenu-functions (node &optional var)
+  "Record function definitions for imenu.
+NODE is a function node or an object literal.
+VAR, if non-nil, is the expression that NODE is being assigned to."
+  (when js2-parse-ide-mode
+    (let ((fun-p (js2-function-node-p node))
+          qname left fname-node pos)
+      (cond
+       ;; non-anonymous function declaration?
+       ((and fun-p
+             (not var)
+             (setq fname-node (js2-function-node-name node)))
+        (push (setq qname (list fname-node (js2-node-pos node)))
+              js2-imenu-recorder)
+        (js2-record-function-qname node qname))
+       ;; for remaining forms, compute left-side tree branch first
+       ((and var (setq qname (js2-compute-nested-prop-get var)))
+        (cond
+         ;; foo.bar.baz = function
+         (fun-p
+          (push (nconc qname (list (js2-node-pos node)))
+                js2-imenu-recorder)
+          (js2-record-function-qname node qname))
+         ;; foo.bar.baz = object-literal
+         ;; look for nested functions:  {a: {b: function() {...} }}
+         ((js2-object-node-p node)
+          (js2-record-object-literal node qname))))))))
+
+(defun js2-compute-nested-prop-get (node)
+  "If NODE is of form foo.bar.baz, return component nodes as a list.
+Otherwise returns nil.  Element-gets can be treated as property-gets
+if the index expression is a name, a string, or a positive integer."
+  (let (left right head)
+    (cond
+     ((or (js2-name-node-p node)
+          (js2-this-node-p node))
+      (list node))
+     ;; foo.bar.baz is parenthesized as (foo.bar).baz => right operand is a 
leaf
+     ((js2-prop-get-node-p node)  ; includes elem-get nodes
+      (setq left (js2-prop-get-node-left node)
+            right (js2-prop-get-node-right node))
+      (if (and (or (js2-prop-get-node-p left)     ; left == foo.bar
+                   (js2-name-node-p left)
+                   (js2-this-node-p left))        ; or left == foo
+               (or (js2-name-node-p right)        ; .bar
+                   (js2-string-node-p right)      ; ['bar']
+                   (and (js2-number-node-p right) ; [10]
+                        (string-match "^[0-9]+$"
+                                      (js2-number-node-value right)))))
+          (if (setq head (js2-compute-nested-prop-get left))
+              (nconc head (list right))))))))
+
+(defun js2-record-object-literal (node qname)
+  "Recursively process an object literal looking for functions.
+NODE is an object literal that is the right-hand child of an assignment
+expression.  QNAME is a list of nodes representing the assignment target,
+e.g. for foo.bar.baz = {...}, QNAME is (foo-node bar-node baz-node).
+We do a depth-first traversal of NODE.  Any functions we find are prefixed
+with QNAME plus the property name of the function and appended to the
+variable `js2-imenu-recorder'."
+  ;; Elements are relative to parent position, which is still absolute,
+  ;; since the parser passes the assignment target and value expressions
+  ;; to us before they are added as children of the assignment node.
+  (let ((pos (js2-node-pos node))
+        left right)
+    (dolist (e (js2-object-node-elems node))  ; e is a `js2-object-prop-node'
+      (setq left (js2-infix-node-left e))
+      (cond
+       ;; foo: function() {...}
+       ((js2-function-node-p (setq right (js2-infix-node-right e)))
+        (when (js2-prop-node-name left)
+          ;; As a policy decision, we record the position of the property,
+          ;; not the position of the `function' keyword, since the property
+          ;; is effectively the name of the function.
+          (push (append qname (list left) (list (+ pos (js2-node-pos e))))
+                js2-imenu-recorder)
+          (js2-record-function-qname right qname)))
+       ;; foo: {object-literal} -- add foo to qname and recurse
+       ((js2-object-node-p right)
+        (js2-record-object-literal right
+                                   (append qname (list (js2-infix-node-left 
e)))))))))
+
+(defsubst js2-node-top-level-decl-p (node)
+  "Return t if NODE's name is defined in the top-level scope.
+Also returns t if NODE's name is not defined in any scope, since it implies
+that it's an external variable, which must also be in the top-level scope."
+  (let* ((name (js2-prop-node-name node))
+         (this-scope (js2-node-get-enclosing-scope node))
+         defining-scope)
+    (cond
+     ((js2-this-node-p node)
+      nil)
+     ((null this-scope)
+      t)
+     ((setq defining-scope (js2-get-defining-scope this-scope name))
+      (js2-ast-root-p defining-scope))
+     (t t))))
+
+(defun js2-browse-postprocess-chains (chains)
+  "Modify function-declaration name chains after parsing finishes.
+Some of the information is only available after the parse tree is complete.
+For instance, following a 'this' reference requires a parent function node."
+  (let (result head fn parent-chain p elem)
+    (dolist (chain chains)
+      ;; examine the head of each node to get its defining scope
+      (setq head (car chain))
+      (cond
+       ;; if top-level/external, keep as-is
+       ((js2-node-top-level-decl-p head)
+        (push chain result))
+       ;; check for a this-reference
+       ((eq (js2-node-type head) js2-THIS)
+        (setq fn (js2-node-parent-script-or-fn head))
+        ;; if there is no parent function, or if the parent function
+        ;; is nested, discard the head node and keep the rest of the chain.
+        (if (or (null fn) (js2-nested-function-p fn))
+            (push (cdr chain) result)
+          ;; else look up parent in function-map.  If not found, discard chain.
+          (when (setq parent-chain (and js2-imenu-function-map
+                                        (gethash fn js2-imenu-function-map)))
+            ;; else discard head node and prefix parent fn qname, which is
+            ;; the parent-chain sans tail, to this chain.
+            (push (append (butlast parent-chain) (cdr chain)) result))))))
+    ;; finally replace each node in each chain with its name.
+    (dolist (chain result)
+      (setq p chain)
+      (while p
+        (if (js2-node-p (setq elem (car p)))
+            (setcar p (js2-node-qname-component elem)))
+        (setq p (cdr p))))
+    result))
+
+;; Merge name chains into a trie-like tree structure of nested lists.
+;; To simplify construction of the trie, we first build it out using the rule
+;; that the trie consists of lists of pairs.  Each pair is a 2-element array:
+;; [key, num-or-list].  The second element can be a number; if so, this key
+;; is a leaf-node with only one value.  (I.e. there is only one declaration
+;; associated with the key at this level.)  Otherwise the second element is
+;; a list of pairs, with the rule applied recursively.  This symmetry permits
+;; a simple recursive formulation.
+;;
+;; js2-mode is building the data structure for imenu.  The imenu documentation
+;; claims that it's the structure above, but in practice it wants the children
+;; at the same list level as the key for that level, which is how I've drawn
+;; the "Expected final result" above.  We'll postprocess the trie to remove the
+;; list wrapper around the children at each level.
+;;
+;; A completed nested imenu-alist entry looks like this:
+;;       '(("foo"
+;;          ("<definition>" . 7)
+;;          ("bar"
+;;           ("a" . 40)
+;;           ("b" . 60))))
+;;
+;; In particular, the documentation for `imenu--index-alist' says that
+;; a nested sub-alist element looks like (INDEX-NAME SUB-ALIST).
+;; The sub-alist entries immediately follow INDEX-NAME, the head of the list.
+
+(defsubst js2-treeify (lst)
+  "Convert (a b c d) to (a ((b ((c d)))))"
+  (if (null (cddr lst))  ; list length <= 2
+      lst
+    (list (car lst) (list (js2-treeify (cdr lst))))))
+
+(defun js2-build-alist-trie (chains trie)
+  "Merge declaration name chains into a trie-like alist structure for imenu.
+CHAINS is the qname chain list produced during parsing. TRIE is a
+list of elements built up so far."
+  (let (head tail pos branch kids)
+    (dolist (chain chains)
+      (setq head (car chain)
+            tail (cdr chain)
+            pos (if (numberp (car tail)) (car tail))
+            branch (js2-find-if (lambda (n)
+                                  (string= (car n) head))
+                                trie)
+            kids (second branch))
+      (cond
+       ;; case 1:  this key isn't in the trie yet
+       ((null branch)
+        (if trie
+            (setcdr (last trie) (list (js2-treeify chain)))
+          (setq trie (list (js2-treeify chain)))))
+       ;; case 2:  key is present with a single number entry:  replace w/ list
+       ;;  ("a1" 10)  +  ("a1" 20) => ("a1" (("<definition>" 10)
+       ;;                                    ("<definition>" 20)))
+       ((numberp kids)
+        (setcar (cdr branch)
+                (list (list "<definition-1>" kids)
+                      (if pos
+                          (list "<definition-2>" pos)
+                        (js2-treeify tail)))))
+       ;; case 3:  key is there (with kids), and we're a number entry
+       (pos
+        (setcdr (last kids)
+                (list
+                 (list (format "<definition-%d>"
+                               (1+ (loop for kid in kids
+                                         count (eq ?< (aref (car kid) 0)))))
+                       pos))))
+       ;; case 4:  key is there with kids, need to merge in our chain
+       (t
+        (js2-build-alist-trie (list tail) kids))))
+    trie))
+
+(defun js2-flatten-trie (trie)
+  "Convert TRIE to imenu-format.
+Recurses through nodes, and for each one whose second element is a list,
+appends the list's flattened elements to the current element.  Also
+changes the tails into conses.  For instance, this pre-flattened trie
+
+'(a ((b 20)
+     (c ((d 30)
+         (e 40)))))
+
+becomes
+
+'(a (b . 20)
+    (c (d . 30)
+       (e . 40)))
+
+Note that the root of the trie has no key, just a list of chains.
+This is also true for the value of any key with multiple children,
+e.g. key 'c' in the example above."
+  (cond
+   ((listp (car trie))
+    (mapcar #'js2-flatten-trie trie))
+   (t
+    (if (numberp (second trie))
+        (cons (car trie) (second trie))
+      ;; else pop list and append its kids
+      (apply #'append (list (car trie)) (js2-flatten-trie (cdr trie)))))))
+
+(defun js2-build-imenu-index ()
+  "Turn `js2-imenu-recorder' into an imenu data structure."
+  (unless (eq js2-imenu-recorder 'empty)
+    (let* ((chains (js2-browse-postprocess-chains js2-imenu-recorder))
+           (result (js2-build-alist-trie chains nil)))
+      (js2-flatten-trie result))))
+
+(defun js2-test-print-chains (chains)
+  "Print a list of qname chains.
+Each element of CHAINS is a list of the form (NODE [NODE *] pos);
+i.e. one or more nodes, and an integer position as the list tail."
+  (mapconcat (lambda (chain)
+               (concat "("
+                       (mapconcat (lambda (elem)
+                                    (if (js2-node-p elem)
+                                        (or (js2-node-qname-component elem)
+                                            "nil")
+                                      (number-to-string elem)))
+                                  chain
+                                  " ")
+                       ")"))
+             chains
+             "\n"))
+
+;;; Parser
+
+(defconst js2-version "1.8.0"
+  "Version of JavaScript supported, plus minor js2 version.")
+
+(defmacro js2-record-face (face)
+  "Record a style run of FACE for the current token."
+  `(js2-set-face js2-token-beg js2-token-end ,face 'record))
+
+(defsubst js2-node-end (n)
+  "Computes the absolute end of node N.
+Use with caution!  Assumes `js2-node-pos' is -absolute-, which
+is only true until the node is added to its parent; i.e., while parsing."
+  (+ (js2-node-pos n)
+     (js2-node-len n)))
+
+(defsubst js2-record-comment ()
+  "Record a comment in `js2-scanned-comments'."
+  (push (make-js2-comment-node :len (- js2-token-end js2-token-beg)
+                               :format js2-ts-comment-type)
+        js2-scanned-comments)
+  (when js2-parse-ide-mode
+    (js2-record-face (if (eq js2-ts-comment-type 'jsdoc)
+                         'font-lock-doc-face
+                       'font-lock-comment-face))
+    (when (memq js2-ts-comment-type '(html preprocessor))
+      ;; Tell cc-engine the bounds of the comment.
+      (put-text-property js2-token-beg (1- js2-token-end) 'c-in-sws t))))
+
+;; This function is called depressingly often, so it should be fast.
+;; Most of the time it's looking at the same token it peeked before.
+(defsubst js2-peek-token ()
+  "Returns the next token without consuming it.
+If previous token was consumed, calls scanner to get new token.
+If previous token was -not- consumed, returns it (idempotent).
+
+This function will not return a newline (js2-EOL) - instead, it
+gobbles newlines until it finds a non-newline token, and flags
+that token as appearing just after a newline.
+
+This function will also not return a js2-COMMENT.  Instead, it
+records comments found in `js2-scanned-comments'.  If the token
+returned by this function immediately follows a jsdoc comment,
+the token is flagged as such.
+
+Note that this function always returned the un-flagged token!
+The flags, if any, are saved in `js2-current-flagged-token'."
+  (if (/= js2-current-flagged-token js2-EOF) ; last token not consumed
+      js2-current-token  ; most common case - return already-peeked token
+    (let ((tt (js2-get-token))          ; call scanner
+          saw-eol
+          face)
+      ;; process comments and whitespace
+      (while (or (= tt js2-EOL)
+                 (= tt js2-COMMENT))
+        (if (= tt js2-EOL)
+            (setq saw-eol t)
+          (setq saw-eol nil)
+          (if js2-record-comments
+              (js2-record-comment)))
+        (setq tt (js2-get-token)))  ; call scanner
+      (setq js2-current-token tt
+            js2-current-flagged-token (if saw-eol
+                                          (logior tt js2-ti-after-eol)
+                                        tt))
+      ;; perform lexical fontification as soon as token is scanned
+      (when js2-parse-ide-mode
+        (cond
+         ((minusp tt)
+          (js2-record-face 'js2-error-face))
+         ((setq face (aref js2-kwd-tokens tt))
+          (js2-record-face face))
+         ((and (= tt js2-NAME)
+               (equal js2-ts-string "undefined"))
+          (js2-record-face 'font-lock-constant-face))))
+      tt)))  ; return unflagged token
+
+(defsubst js2-peek-flagged-token ()
+  "Returns the current token along with any flags set for it."
+  (js2-peek-token)
+  js2-current-flagged-token)
+
+(defsubst js2-consume-token ()
+  (setq js2-current-flagged-token js2-EOF))
+
+(defsubst js2-next-token ()
+  (prog1
+      (js2-peek-token)
+    (js2-consume-token)))
+
+(defsubst js2-next-flagged-token ()
+  (js2-peek-token)
+  (prog1 js2-current-flagged-token
+    (js2-consume-token)))
+
+(defsubst js2-match-token (match)
+  "Consume and return t if next token matches MATCH, a bytecode.
+Returns nil and consumes nothing if MATCH is not the next token."
+  (if (/= (js2-peek-token) match)
+      nil
+    (js2-consume-token)
+    t))
+
+(defsubst js2-valid-prop-name-token (tt)
+  (or (= tt js2-NAME)
+      (and js2-allow-keywords-as-property-names
+           (plusp tt)
+           (aref js2-kwd-tokens tt))))
+
+(defsubst js2-match-prop-name ()
+  "Consume token and return t if next token is a valid property name.
+It's valid if it's a js2-NAME, or `js2-allow-keywords-as-property-names'
+is non-nil and it's a keyword token."
+  (if (js2-valid-prop-name-token (js2-peek-token))
+      (progn
+        (js2-consume-token)
+        t)
+    nil))
+
+(defsubst js2-must-match-prop-name (msg-id &optional pos len)
+  (if (js2-match-prop-name)
+      t
+    (js2-report-error msg-id nil pos len)
+    nil))
+
+(defsubst js2-peek-token-or-eol ()
+  "Return js2-EOL if the current token immediately follows a newline.
+Else returns the current token.  Used in situations where we don't
+consider certain token types valid if they are preceded by a newline.
+One example is the postfix ++ or -- operator, which has to be on the
+same line as its operand."
+  (let ((tt (js2-peek-token)))
+    ;; Check for last peeked token flags
+    (if (js2-flag-set-p js2-current-flagged-token js2-ti-after-eol)
+        js2-EOL
+      tt)))
+
+(defsubst js2-set-check-for-label ()
+  (assert (= (logand js2-current-flagged-token js2-clear-ti-mask) js2-NAME))
+  (js2-set-flag js2-current-flagged-token js2-ti-check-label))
+
+(defsubst js2-must-match (token msg-id &optional pos len)
+  "Match next token to token code TOKEN, or record a syntax error.
+MSG-ID is the error message to report if the match fails.
+Returns t on match, nil if no match."
+  (if (js2-match-token token)
+      t
+    (js2-report-error msg-id nil pos len)
+    nil))
+
+(defsubst js2-inside-function ()
+  (plusp js2-nesting-of-function))
+
+(defsubst js2-set-requires-activation ()
+  (if (js2-function-node-p js2-current-script-or-fn)
+      (setf (js2-function-node-needs-activation js2-current-script-or-fn) t)))
+
+(defsubst js2-check-activation-name (name token)
+  (when (js2-inside-function)
+    ;; skip language-version 1.2 check from Rhino
+    (if (or (string= "arguments" name)
+            (and js2-compiler-activation-names  ; only used in codegen
+                 (gethash name js2-compiler-activation-names)))
+        (js2-set-requires-activation))))
+
+(defsubst js2-set-is-generator ()
+  (if (js2-function-node-p js2-current-script-or-fn)
+      (setf (js2-function-node-is-generator js2-current-script-or-fn) t)))
+
+(defsubst js2-must-have-xml ()
+  (unless js2-compiler-xml-available
+    (js2-report-error "msg.XML.not.available")))
+
+(defsubst js2-push-scope (scope)
+  "Push SCOPE, a `js2-scope', onto the lexical scope chain."
+  (assert (js2-scope-p scope))
+  (assert (null (js2-scope-parent-scope scope)))
+  (assert (not (eq js2-current-scope scope)))
+  (setf (js2-scope-parent-scope scope) js2-current-scope
+        js2-current-scope scope))
+
+(defsubst js2-pop-scope ()
+  (setq js2-current-scope
+        (js2-scope-parent-scope js2-current-scope)))
+
+(defsubst js2-enter-loop (loop-node)
+  (push loop-node js2-loop-set)
+  (push loop-node js2-loop-and-switch-set)
+  (js2-push-scope loop-node)
+  ;; Tell the current labeled statement (if any) its statement,
+  ;; and set the jump target of the first label to the loop.
+  ;; These are used in `js2-parse-continue' to verify that the
+  ;; continue target is an actual labeled loop.  (And for codegen.)
+  (when js2-labeled-stmt
+    (setf (js2-labeled-stmt-node-stmt js2-labeled-stmt) loop-node
+          (js2-label-node-loop (car (js2-labeled-stmt-node-labels
+                                     js2-labeled-stmt))) loop-node)))
+
+(defsubst js2-exit-loop ()
+  (pop js2-loop-set)
+  (pop js2-loop-and-switch-set)
+  (js2-pop-scope))
+
+(defsubst js2-enter-switch (switch-node)
+  (push switch-node js2-loop-and-switch-set))
+
+(defsubst js2-exit-switch ()
+  (pop js2-loop-and-switch-set))
+
+(defun js2-parse (&optional buf cb)
+  "Tells the js2 parser to parse a region of JavaScript.
+
+BUF is a buffer or buffer name containing the code to parse.
+Call `narrow-to-region' first to parse only part of the buffer.
+
+The returned AST root node is given some additional properties:
+  `node-count' - total number of nodes in the AST
+  `buffer' - BUF.  The buffer it refers to may change or be killed,
+             so the value is not necessarily reliable.
+
+An optional callback CB can be specified to report parsing
+progress.  If `(functionp CB)' returns t, it will be called with
+the current line number once before parsing begins, then again
+each time the lexer reaches a new line number.
+
+CB can also be a list of the form `(symbol cb ...)' to specify
+multiple callbacks with different criteria.  Each symbol is a
+criterion keyword, and the following element is the callback to
+call
+
+  :line  - called whenever the line number changes
+  :token - called for each new token consumed
+
+The list of criteria could be extended to include entering or
+leaving a statement, an expression, or a function definition."
+  (if (and cb (not (functionp cb)))
+      (error "criteria callbacks not yet implemented"))
+  (let ((inhibit-point-motion-hooks t)
+        (js2-compiler-xml-available (>= js2-language-version 160))
+        ;; This is a recursive-descent parser, so give it a big stack.
+        (max-lisp-eval-depth (max max-lisp-eval-depth 3000))
+        (max-specpdl-size (max max-specpdl-size 3000))
+        (case-fold-search nil)
+        ast)
+    (or buf (setq buf (current-buffer)))
+    (message nil)  ; clear any error message from previous parse
+    (save-excursion
+      (set-buffer buf)
+      (setq js2-scanned-comments nil
+            js2-parsed-errors nil
+            js2-parsed-warnings nil
+            js2-imenu-recorder nil
+            js2-imenu-function-map nil
+            js2-label-set nil)
+      (js2-init-scanner)
+      (setq ast (js2-with-unmodifying-text-property-changes
+                  (js2-do-parse)))
+      (unless js2-ts-hit-eof
+        (js2-report-error "msg.got.syntax.errors" (length js2-parsed-errors)))
+      (setf (js2-ast-root-errors ast) js2-parsed-errors
+            (js2-ast-root-warnings ast) js2-parsed-warnings)
+      ;; if we didn't find any declarations, put a dummy in this list so we
+      ;; don't end up re-parsing the buffer in `js2-mode-create-imenu-index'
+      (unless js2-imenu-recorder
+        (setq js2-imenu-recorder 'empty))
+      (run-hooks 'js2-parse-finished-hook)
+      ast)))
+
+;; Corresponds to Rhino's Parser.parse() method.
+(defun js2-do-parse ()
+  "Parse current buffer starting from current point.
+Scanner should be initialized."
+  (let ((pos js2-ts-cursor)
+        (end js2-ts-cursor)  ; in case file is empty
+        root n tt)
+    ;; initialize buffer-local parsing vars
+    (setf root (make-js2-ast-root :buffer (buffer-name) :pos pos)
+          js2-current-script-or-fn root
+          js2-current-scope root
+          js2-current-flagged-token js2-EOF
+          js2-nesting-of-function 0
+          js2-labeled-stmt nil
+          js2-recorded-assignments nil)  ; for js2-highlight
+    (while (/= (setq tt (js2-peek-token)) js2-EOF)
+      (if (= tt js2-FUNCTION)
+          (progn
+            (js2-consume-token)
+            (setq n (js2-parse-function (if js2-called-by-compile-function
+                                            'FUNCTION_EXPRESSION
+                                          'FUNCTION_STATEMENT)))
+            (js2-record-imenu-functions n))
+        ;; not a function - parse a statement
+        (setq n (js2-parse-statement)))
+      ;; add function or statement to script
+      (setq end (js2-node-end n))
+      (js2-block-node-push root n))
+    ;; add comments to root in lexical order
+    (when js2-scanned-comments
+      ;; if we find a comment beyond end of normal kids, use its end
+      (setq end (max end (js2-node-end (first js2-scanned-comments))))
+      (dolist (comment js2-scanned-comments)
+        (push comment (js2-ast-root-comments root))
+        (js2-node-add-children root comment)))
+    (setf (js2-node-len root) (- end pos))
+    ;; Give extensions a chance to muck with things before highlighting starts.
+    (dolist (callback js2-post-parse-callbacks)
+      (funcall callback))
+    (js2-highlight-undeclared-vars)
+    root))
+
+(defun js2-function-parser ()
+  (js2-consume-token)
+  (js2-parse-function 'FUNCTION_EXPRESSION_STATEMENT))
+
+(defun js2-parse-function-closure-body (fn-node)
+  "Parse a JavaScript 1.8 function closure body."
+  (let ((js2-nesting-of-function (1+ js2-nesting-of-function)))
+    (if js2-ts-hit-eof
+        (js2-report-error "msg.no.brace.body" nil
+                          (js2-node-pos fn-node)
+                          (- js2-ts-cursor (js2-node-pos fn-node)))
+      (js2-node-add-children fn-node
+                             (setf (js2-function-node-body fn-node)
+                                   (js2-parse-expr))))))
+
+(defun js2-parse-function-body (fn-node)
+  (js2-must-match js2-LC "msg.no.brace.body"
+                  (js2-node-pos fn-node)
+                  (- js2-ts-cursor (js2-node-pos fn-node)))
+  (let ((pos js2-token-beg)         ; LC position
+        (pn (make-js2-block-node))  ; starts at LC position
+        tt
+        end)
+    (incf js2-nesting-of-function)
+    (unwind-protect
+        (while (not (or (= (setq tt (js2-peek-token)) js2-ERROR)
+                        (= tt js2-EOF)
+                        (= tt js2-RC)))
+          (js2-block-node-push pn (if (/= tt js2-FUNCTION)
+                                      (js2-parse-statement)
+                                    (js2-consume-token)
+                                    (js2-parse-function 'FUNCTION_STATEMENT))))
+      (decf js2-nesting-of-function))
+    (setq end js2-token-end)  ; assume no curly and leave at current token
+    (if (js2-must-match js2-RC "msg.no.brace.after.body" pos)
+        (setq end js2-token-end))
+    (setf (js2-node-pos pn) pos
+          (js2-node-len pn) (- end pos))
+    (setf (js2-function-node-body fn-node) pn)
+    (js2-node-add-children fn-node pn)
+    pn))
+
+(defun js2-parse-function-params (fn-node pos)
+  (if (js2-match-token js2-RP)
+      (setf (js2-function-node-rp fn-node) (- js2-token-beg pos))
+    (let (params len param)
+      (loop for tt = (js2-peek-token)
+            do
+            (cond
+             ;; destructuring param
+             ((or (= tt js2-LB) (= tt js2-LC))
+              (push (js2-parse-primary-expr) params))
+             ;; simple name
+             (t
+              (js2-must-match js2-NAME "msg.no.parm")
+              (js2-record-face 'js2-function-param-face)
+              (setq param (js2-create-name-node))
+              (js2-define-symbol js2-LP js2-ts-string param)
+              (push param params)))
+            while
+            (js2-match-token js2-COMMA))
+      (if (js2-must-match js2-RP "msg.no.paren.after.parms")
+          (setf (js2-function-node-rp fn-node) (- js2-token-beg pos)))
+      (dolist (p params)
+        (js2-node-add-children fn-node p)
+        (push p (js2-function-node-params fn-node))))))
+
+(defsubst js2-check-inconsistent-return-warning (fn-node name)
+  "Possibly show inconsistent-return warning.
+Last token scanned is the close-curly for the function body."
+  (when (and js2-mode-show-strict-warnings
+             js2-strict-inconsistent-return-warning
+             (not (js2-has-consistent-return-usage
+                   (js2-function-node-body fn-node))))
+    ;; Have it extend from close-curly to bol or beginning of block.
+    (let ((pos (save-excursion
+                 (goto-char js2-token-end)
+                 (max (js2-node-abs-pos (js2-function-node-body fn-node))
+                      (point-at-bol))))
+          (end js2-token-end))
+      (if (plusp (js2-name-node-length name))
+          (js2-add-strict-warning "msg.no.return.value"
+                                  (js2-name-node-name name) pos end)
+        (js2-add-strict-warning "msg.anon.no.return.value" nil pos end)))))
+
+(defun js2-parse-function (function-type)
+  "Function parser.  FUNCTION-TYPE is a symbol."
+  (let ((pos js2-token-beg)  ; start of 'function' keyword
+        name
+        name-beg
+        name-end
+        fn-node
+        lp
+        (synthetic-type function-type)
+        member-expr-node)
+    ;; parse function name, expression, or non-name (anonymous)
+    (cond
+     ;; function foo(...)
+     ((js2-match-token js2-NAME)
+      (setq name (js2-create-name-node t)
+            name-beg js2-token-beg
+            name-end js2-token-end)
+      (unless (js2-match-token js2-LP)
+        (when js2-allow-member-expr-as-function-name
+          ;; function foo.bar(...)
+          (setq member-expr-node name
+                name nil
+                member-expr-node (js2-parse-member-expr-tail
+                                  nil member-expr-node)))
+        (js2-must-match js2-LP "msg.no.paren.parms")))
+     ((js2-match-token js2-LP)
+      nil)  ; anonymous function:  leave name as null
+     (t
+      ;; function random-member-expr(...)
+      (when js2-allow-member-expr-as-function-name
+        ;; Note that memberExpr can not start with '(' like
+        ;; in function (1+2).toString(), because 'function (' already
+        ;; processed as anonymous function
+        (setq member-expr-node (js2-parse-member-expr)))
+      (js2-must-match js2-LP "msg.no.paren.parms")))
+    (if (= js2-current-token js2-LP)  ; eventually matched LP?
+        (setq lp js2-token-beg))
+    (if member-expr-node
+        (progn
+          (setq synthetic-type 'FUNCTION_EXPRESSION)
+          (js2-parse-highlight-member-expr-fn-name member-expr-node))
+      (if name
+          (js2-set-face name-beg name-end
+                        'font-lock-function-name-face 'record)))
+    (if (and (not (eq synthetic-type 'FUNCTION_EXPRESSION))
+             (plusp (js2-name-node-length name)))
+        ;; Function statements define a symbol in the enclosing scope
+        (js2-define-symbol js2-FUNCTION (js2-name-node-name name) fn-node))
+    (setf fn-node (make-js2-function-node :pos pos
+                                          :name name
+                                          :form function-type
+                                          :lp (if lp (- lp pos))))
+    (if (or (js2-inside-function) (plusp js2-nesting-of-with))
+        ;; 1. Nested functions are not affected by the dynamic scope flag
+        ;;    as dynamic scope is already a parent of their scope.
+        ;; 2. Functions defined under the with statement also immune to
+        ;;    this setup, in which case dynamic scope is ignored in favor
+        ;;    of the with object.
+        (setf (js2-function-node-ignore-dynamic fn-node) t))
+    ;; dynamically bind all the per-function variables
+    (let ((js2-current-script-or-fn fn-node)
+          (js2-current-scope fn-node)
+          (js2-nesting-of-with 0)
+          (js2-end-flags 0)
+          js2-label-set
+          js2-loop-set
+          js2-loop-and-switch-set)
+      (js2-parse-function-params fn-node pos)
+      (if (and (>= js2-language-version 180)
+               (/= (js2-peek-token) js2-LC))
+          (js2-parse-function-closure-body fn-node)
+        (js2-parse-function-body fn-node))
+      (if name
+          (js2-node-add-children fn-node name))
+      (js2-check-inconsistent-return-warning fn-node name)
+      ;; Function expressions define a name only in the body of the
+      ;; function, and only if not hidden by a parameter name
+      (if (and name
+               (eq synthetic-type 'FUNCTION_EXPRESSION)
+               (null (js2-scope-get-symbol js2-current-scope
+                                           (js2-name-node-name name))))
+          (js2-define-symbol js2-FUNCTION
+                             (js2-name-node-name name)
+                             fn-node))
+      (if (and name
+               (eq function-type 'FUNCTION_EXPRESSION_STATEMENT))
+          (js2-record-imenu-functions fn-node)))
+    (setf (js2-node-len fn-node) (- js2-ts-cursor pos)
+          (js2-function-node-member-expr fn-node) member-expr-node)  ; may be 
nil
+    ;; Rhino doesn't do this, but we need it for finding undeclared vars.
+    ;; We wait until after parsing the function to set its parent scope,
+    ;; since `js2-define-symbol' needs the defining-scope check to stop
+    ;; at the function boundary when checking for redeclarations.
+    (setf (js2-scope-parent-scope fn-node) js2-current-scope)
+    fn-node))
+
+(defun js2-parse-statements (&optional parent)
+  "Parse a statement list.  Last token consumed must be js2-LC.
+
+PARENT can be a `js2-block-node', in which case the statements are
+appended to PARENT.  Otherwise a new `js2-block-node' is created
+and returned.
+
+This function does not match the closing js2-RC: the caller
+matches the RC so it can provide a suitable error message if not
+matched.  This means it's up to the caller to set the length of
+the node to include the closing RC.  The node start pos is set to
+the absolute buffer start position, and the caller should fix it
+up to be relative to the parent node.  All children of this block
+node are given relative start positions and correct lengths."
+  (let ((pn (or parent (make-js2-block-node)))
+        tt)
+    (setf (js2-node-pos pn) js2-token-beg)
+    (while (and (> (setq tt (js2-peek-token)) js2-EOF)
+                (/= tt js2-RC))
+      (js2-block-node-push pn (js2-parse-statement)))
+    pn))
+
+(defun js2-parse-statement ()
+  (let (tt pn beg end)
+    ;; coarse-grained user-interrupt check - needs work
+    (and js2-parse-interruptable-p
+         (zerop (% (incf js2-parse-stmt-count)
+                   js2-statements-per-pause))
+         (input-pending-p)
+         (throw 'interrupted t))
+    (setq pn (js2-statement-helper))
+    ;; no-side-effects warning check
+    (unless (js2-node-has-side-effects pn)
+      (setq end (js2-node-end pn))
+      (save-excursion
+        (goto-char end)
+        (setq beg (max (js2-node-pos pn) (point-at-bol))))
+      (js2-add-strict-warning "msg.no.side.effects" nil beg end))
+    pn))
+
+;; These correspond to the switch cases in Parser.statementHelper
+(defconst js2-parsers
+  (let ((parsers (make-vector js2-num-tokens
+                                #'js2-parse-expr-stmt)))
+    (aset parsers js2-BREAK     #'js2-parse-break)
+    (aset parsers js2-CONST     #'js2-parse-const-var)
+    (aset parsers js2-CONTINUE  #'js2-parse-continue)
+    (aset parsers js2-DEBUGGER  #'js2-parse-debugger)
+    (aset parsers js2-DEFAULT   #'js2-parse-default-xml-namespace)
+    (aset parsers js2-DO        #'js2-parse-do)
+    (aset parsers js2-FOR       #'js2-parse-for)
+    (aset parsers js2-FUNCTION  #'js2-function-parser)
+    (aset parsers js2-IF        #'js2-parse-if)
+    (aset parsers js2-LC        #'js2-parse-block)
+    (aset parsers js2-LET       #'js2-parse-let-stmt)
+    (aset parsers js2-NAME      #'js2-parse-name-or-label)
+    (aset parsers js2-RETURN    #'js2-parse-ret-yield)
+    (aset parsers js2-SEMI      #'js2-parse-semi)
+    (aset parsers js2-SWITCH    #'js2-parse-switch)
+    (aset parsers js2-THROW     #'js2-parse-throw)
+    (aset parsers js2-TRY       #'js2-parse-try)
+    (aset parsers js2-VAR       #'js2-parse-const-var)
+    (aset parsers js2-WHILE     #'js2-parse-while)
+    (aset parsers js2-WITH      #'js2-parse-with)
+    (aset parsers js2-YIELD     #'js2-parse-ret-yield)
+    parsers)
+  "A vector mapping token types to parser functions.")
+
+(defsubst js2-parse-warn-missing-semi (beg end)
+  (and js2-mode-show-strict-warnings
+       js2-strict-missing-semi-warning
+       (js2-add-strict-warning
+        "msg.missing.semi" nil
+        ;; back up to beginning of statement or line
+        (max beg (save-excursion
+                   (goto-char end)
+                   (point-at-bol)))
+        end)))
+
+(defconst js2-no-semi-insertion
+  (list js2-IF
+        js2-SWITCH
+        js2-WHILE
+        js2-DO
+        js2-FOR
+        js2-TRY
+        js2-WITH
+        js2-LC
+        js2-ERROR
+        js2-SEMI
+        js2-FUNCTION)
+  "List of tokens that don't do automatic semicolon insertion.")
+
+(defconst js2-autoinsert-semi-and-warn
+  (list js2-ERROR js2-EOF js2-RC))
+
+(defun js2-statement-helper ()
+  (let* ((tt (js2-peek-token))
+         (first-tt tt)
+         (beg js2-token-beg)
+         (parser (if (= tt js2-ERROR)
+                     #'js2-parse-semi
+                   (aref js2-parsers tt)))
+         pn
+         tt-flagged)
+    ;; If the statement is set, then it's been told its label by now.
+    (and js2-labeled-stmt
+         (js2-labeled-stmt-node-stmt js2-labeled-stmt)
+         (setq js2-labeled-stmt nil))
+    (setq pn (funcall parser))
+    ;; Don't do auto semi insertion for certain statement types.
+    (unless (or (memq first-tt js2-no-semi-insertion)
+                (js2-labeled-stmt-node-p pn))
+      (js2-auto-insert-semicolon pn))
+    pn))
+
+(defun js2-auto-insert-semicolon (pn)
+  (let* ((tt-flagged (js2-peek-flagged-token))
+         (tt (logand tt-flagged js2-clear-ti-mask))
+         (pos (js2-node-pos pn)))
+      (cond
+       ((= tt js2-SEMI)
+        ;; Consume ';' as a part of expression
+        (js2-consume-token)
+        ;; extend the node bounds to include the semicolon.
+        (setf (js2-node-len pn) (- js2-token-end pos)))
+       ((memq tt js2-autoinsert-semi-and-warn)
+        ;; Autoinsert ;
+        (js2-parse-warn-missing-semi pos (js2-node-end pn)))
+       (t
+        (if (js2-flag-not-set-p tt-flagged js2-ti-after-eol)
+            ;; Report error if no EOL or autoinsert ';' otherwise
+            (js2-report-error "msg.no.semi.stmt")
+          (js2-parse-warn-missing-semi pos (js2-node-end pn)))))))
+
+(defun js2-parse-condition ()
+  "Parse a parenthesized boolean expression, e.g. in an if- or while-stmt.
+The parens are discarded and the expression node is returned.
+The `pos' field of the return value is set to an absolute position
+that must be fixed up by the caller.
+Return value is a list (EXPR LP RP), with absolute paren positions."
+  (let (pn lp rp)
+    (if (js2-must-match js2-LP "msg.no.paren.cond")
+        (setq lp js2-token-beg))
+    (setq pn (js2-parse-expr))
+    (if (js2-must-match js2-RP "msg.no.paren.after.cond")
+        (setq rp js2-token-beg))
+    ;; Report strict warning on code like "if (a = 7) ..."
+    (if (and js2-strict-cond-assign-warning
+             (js2-assign-node-p pn))
+        (js2-add-strict-warning "msg.equal.as.assign" nil
+                                (js2-node-pos pn)
+                                (+ (js2-node-pos pn)
+                                   (js2-node-len pn))))
+    (list pn lp rp)))
+
+(defun js2-parse-if ()
+  "Parser for if-statement.  Last matched token must be js2-IF."
+  (let ((pos js2-token-beg)
+        cond
+        if-true
+        if-false
+        else-pos
+        end
+        pn)
+    (js2-consume-token)
+    (setq cond (js2-parse-condition)
+          if-true (js2-parse-statement)
+          if-false (if (js2-match-token js2-ELSE)
+                       (progn
+                         (setq else-pos (- js2-token-beg pos))
+                         (js2-parse-statement)))
+          end (js2-node-end (or if-false if-true))
+          pn (make-js2-if-node :pos pos
+                               :len (- end pos)
+                               :condition (car cond)
+                               :then-part if-true
+                               :else-part if-false
+                               :else-pos else-pos
+                               :lp (js2-relpos (second cond) pos)
+                               :rp (js2-relpos (third cond) pos)))
+    (js2-node-add-children pn (car cond) if-true if-false)
+    pn))
+
+(defun js2-parse-switch ()
+  "Parser for if-statement.  Last matched token must be js2-SWITCH."
+  (let ((pos js2-token-beg)
+        tt
+        pn
+        discriminant
+        has-default
+        case-expr
+        case-node
+        case-pos
+        cases
+        stmt
+        lp
+        rp)
+    (js2-consume-token)
+    (if (js2-must-match js2-LP "msg.no.paren.switch")
+        (setq lp js2-token-beg))
+    (setq discriminant (js2-parse-expr)
+          pn (make-js2-switch-node :discriminant discriminant
+                                   :pos pos
+                                   :lp (js2-relpos lp pos)))
+    (js2-node-add-children pn discriminant)
+    (js2-enter-switch pn)
+    (unwind-protect
+        (progn
+          (if (js2-must-match js2-RP "msg.no.paren.after.switch")
+              (setf (js2-switch-node-rp pn) (- js2-token-beg pos)))
+          (js2-must-match js2-LC "msg.no.brace.switch")
+          (catch 'break
+            (while t
+              (setq tt (js2-next-token)
+                    case-pos js2-token-beg)
+              (cond
+               ((= tt js2-RC)
+                (setf (js2-node-len pn) (- js2-token-end pos))
+                (throw 'break nil))  ; done
+               ((= tt js2-CASE)
+                (setq case-expr (js2-parse-expr))
+                (js2-must-match js2-COLON "msg.no.colon.case"))
+               ((= tt js2-DEFAULT)
+                (if has-default
+                    (js2-report-error "msg.double.switch.default"))
+                (setq has-default t
+                      case-expr nil)
+                (js2-must-match js2-COLON "msg.no.colon.case"))
+               (t
+                (js2-report-error "msg.bad.switch")
+                (throw 'break nil)))
+              (setq case-node (make-js2-case-node :pos case-pos
+                                                  :len (- js2-token-end 
case-pos)
+                                                  :expr case-expr))
+              (js2-node-add-children case-node case-expr)
+              (while (and (/= (setq tt (js2-peek-token)) js2-RC)
+                          (/= tt js2-CASE)
+                          (/= tt js2-DEFAULT)
+                          (/= tt js2-EOF))
+                (setf stmt (js2-parse-statement)
+                      (js2-node-len case-node) (- (js2-node-end stmt) 
case-pos))
+                (js2-block-node-push case-node stmt))
+              (push case-node cases)))
+          ;; add cases last, as pushing reverses the order to be correct
+          (dolist (kid cases)
+            (js2-node-add-children pn kid)
+            (push kid (js2-switch-node-cases pn)))
+          pn)  ; return value
+      (js2-exit-switch))))
+
+(defun js2-parse-while ()
+  "Parser for while-statement.  Last matched token must be js2-WHILE."
+  (let ((pos js2-token-beg)
+        (pn (make-js2-while-node))
+        cond
+        body)
+    (js2-consume-token)
+    (js2-enter-loop pn)
+    (unwind-protect
+        (progn
+          (setf cond (js2-parse-condition)
+                (js2-while-node-condition pn) (car cond)
+                body (js2-parse-statement)
+                (js2-while-node-body pn) body
+                (js2-node-len pn) (- (js2-node-end body) pos)
+                (js2-while-node-lp pn) (js2-relpos (second cond) pos)
+                (js2-while-node-rp pn) (js2-relpos (third cond) pos))
+          (js2-node-add-children pn body (car cond)))
+      (js2-exit-loop))
+    pn))
+
+(defun js2-parse-do ()
+  "Parser for do-statement.  Last matched token must be js2-DO."
+  (let ((pos js2-token-beg)
+        (pn (make-js2-do-node))
+        cond
+        body
+        end)
+    (js2-consume-token)
+    (js2-enter-loop pn)
+    (unwind-protect
+        (progn
+          (setq body (js2-parse-statement))
+          (js2-must-match js2-WHILE "msg.no.while.do")
+          (setf (js2-do-node-while-pos pn) (- js2-token-beg pos)
+                cond (js2-parse-condition)
+                (js2-do-node-condition pn) (car cond)
+                (js2-do-node-body pn) body
+                end js2-ts-cursor
+                (js2-do-node-lp pn) (js2-relpos (second cond) pos)
+                (js2-do-node-rp pn) (js2-relpos (third cond) pos))
+          (js2-node-add-children pn (car cond) body))
+      (js2-exit-loop))
+    ;; Always auto-insert semicolon to follow SpiderMonkey:
+    ;; It is required by ECMAScript but is ignored by the rest of
+    ;; world; see bug 238945
+    (if (js2-match-token js2-SEMI)
+        (setq end js2-ts-cursor))
+    (setf (js2-node-len pn) (- end pos))
+    pn))
+
+(defun js2-parse-for ()
+  "Parser for for-statement.  Last matched token must be js2-FOR.
+Parses for, for-in, and for each-in statements."
+  (let ((for-pos js2-token-beg)
+        pn
+        is-for-each
+        is-for-in
+        in-pos
+        each-pos
+        tmp-pos
+        init  ; Node init is also foo in 'foo in object'
+        cond  ; Node cond is also object in 'foo in object'
+        incr  ; 3rd section of for-loop initializer
+        body
+        tt
+        lp
+        rp)
+    (js2-consume-token)
+    ;; See if this is a for each () instead of just a for ()
+    (when (js2-match-token js2-NAME)
+      (if (string= "each" js2-ts-string)
+          (progn
+            (setq is-for-each t
+                  each-pos (- js2-token-beg for-pos)) ; relative
+            (js2-record-face 'font-lock-keyword-face))
+        (js2-report-error "msg.no.paren.for")))
+    (if (js2-must-match js2-LP "msg.no.paren.for")
+        (setq lp (- js2-token-beg for-pos)))
+    (setq tt (js2-peek-token))
+    ;; parse init clause
+    (let ((js2-in-for-init t))  ; set as dynamic variable
+      (cond
+       ((= tt js2-SEMI)
+        (setq init (make-js2-empty-expr-node)))
+       ((or (= tt js2-VAR) (= tt js2-LET))
+        (js2-consume-token)
+        (setq init (js2-parse-variables tt js2-token-beg)))
+       (t
+        (setq init (js2-parse-expr)))))
+    (if (js2-match-token js2-IN)
+        (setq is-for-in t
+              in-pos (- js2-token-beg for-pos)
+              cond (js2-parse-expr))  ; object over which we're iterating
+      ;; else ordinary for loop - parse cond and incr
+      (js2-must-match js2-SEMI "msg.no.semi.for")
+      (setq cond (if (= (js2-peek-token) js2-SEMI)
+                     (make-js2-empty-expr-node) ; no loop condition
+                   (js2-parse-expr)))
+      (js2-must-match js2-SEMI "msg.no.semi.for.cond")
+      (setq tmp-pos js2-token-end
+            incr (if (= (js2-peek-token) js2-RP)
+                     (make-js2-empty-expr-node :pos tmp-pos)
+                   (js2-parse-expr))))
+    (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
+        (setq rp (- js2-token-beg for-pos)))
+    (if (not is-for-in)
+        (setq pn (make-js2-for-node :init init
+                                    :condition cond
+                                    :update incr
+                                    :lp lp
+                                    :rp rp))
+      ;; cond could be null if 'in obj' got eaten by the init node.
+      (if (js2-infix-node-p init)
+          ;; it was (foo in bar) instead of (var foo in bar)
+          (setq cond (js2-infix-node-right init)
+                init (js2-infix-node-left init))
+        (if (and (js2-var-decl-node-p init)
+                 (> (length (js2-var-decl-node-kids init)) 1))
+            (js2-report-error "msg.mult.index")))
+      (setq pn (make-js2-for-in-node :iterator init
+                                     :object cond
+                                     :in-pos in-pos
+                                     :foreach-p is-for-each
+                                     :each-pos each-pos
+                                     :lp lp
+                                     :rp rp)))
+    (unwind-protect
+        (progn
+          (js2-enter-loop pn)
+          ;; We have to parse the body -after- creating the loop node,
+          ;; so that the loop node appears in the js2-loop-set, allowing
+          ;; break/continue statements to find the enclosing loop.
+          (setf body (js2-parse-statement)
+                (js2-loop-node-body pn) body
+                (js2-node-pos pn) for-pos
+                (js2-node-len pn) (- (js2-node-end body) for-pos))
+          (js2-node-add-children pn init cond incr body))
+      ;; finally
+      (js2-exit-loop))
+    pn))
+
+(defun js2-parse-try ()
+  "Parser for try-statement.  Last matched token must be js2-TRY."
+  (let ((try-pos js2-token-beg)
+        try-end
+        try-block
+        catch-blocks
+        finally-block
+        saw-default-catch
+        peek
+        var-name
+        catch-cond
+        catch-node
+        guard-kwd
+        catch-pos
+        finally-pos
+        pn
+        block
+        lp
+        rp)
+    (js2-consume-token)
+    (if (/= (js2-peek-token) js2-LC)
+        (js2-report-error "msg.no.brace.try"))
+    (setq try-block (js2-parse-statement)
+          try-end (js2-node-end try-block)
+          peek (js2-peek-token))
+    (cond
+     ((= peek js2-CATCH)
+      (while (js2-match-token js2-CATCH)
+        (setq catch-pos js2-token-beg
+              guard-kwd nil
+              catch-cond nil
+              lp nil
+              rp nil)
+        (if saw-default-catch
+            (js2-report-error "msg.catch.unreachable"))
+        (if (js2-must-match js2-LP "msg.no.paren.catch")
+            (setq lp (- js2-token-beg catch-pos)))
+        (js2-must-match js2-NAME "msg.bad.catchcond")
+        (setq var-name (js2-create-name-node))
+        (if (js2-match-token js2-IF)
+            (setq guard-kwd (- js2-token-beg catch-pos)
+                  catch-cond (js2-parse-expr))
+          (setq saw-default-catch t))
+        (if (js2-must-match js2-RP "msg.bad.catchcond")
+            (setq rp (- js2-token-beg catch-pos)))
+        (js2-must-match js2-LC "msg.no.brace.catchblock")
+        (setq block (js2-parse-statements)
+              try-end (js2-node-end block)
+              catch-node (make-js2-catch-node :pos catch-pos
+                                              :var-name var-name
+                                              :guard-expr catch-cond
+                                              :guard-kwd guard-kwd
+                                              :block block
+                                              :lp lp
+                                              :rp rp))
+        (if (js2-must-match js2-RC "msg.no.brace.after.body")
+            (setq try-end js2-token-beg))
+        (setf (js2-node-len block) (- try-end (js2-node-pos block))
+              (js2-node-len catch-node) (- try-end catch-pos))
+        (js2-node-add-children catch-node var-name catch-cond block)
+        (push catch-node catch-blocks)))
+     ((/= peek js2-FINALLY)
+      (js2-must-match js2-FINALLY "msg.try.no.catchfinally"
+                      (js2-node-pos try-block)
+                      (- (setq try-end (js2-node-end try-block))
+                         (js2-node-pos try-block)))))
+    (when (js2-match-token js2-FINALLY)
+      (setq finally-pos js2-token-beg
+            block (js2-parse-statement)
+            try-end (js2-node-end block)
+            finally-block (make-js2-finally-node :pos finally-pos
+                                                 :len (- try-end finally-pos)
+                                                 :body block))
+      (js2-node-add-children finally-block block))
+    (setq pn (make-js2-try-node :pos try-pos
+                                :len (- try-end try-pos)
+                                :try-block try-block
+                                :finally-block finally-block))
+    (js2-node-add-children pn try-block finally-block)
+    ;; push them onto the try-node, which reverses and corrects their order
+    (dolist (cb catch-blocks)
+      (js2-node-add-children pn cb)
+      (push cb (js2-try-node-catch-clauses pn)))
+    pn))
+
+(defun js2-parse-throw ()
+  "Parser for throw-statement.  Last matched token must be js2-THROW."
+  (let ((pos js2-token-beg)
+        expr
+        pn)
+    (js2-consume-token)
+    (if (= (js2-peek-token-or-eol) js2-EOL)
+        ;; ECMAScript does not allow new lines before throw expression,
+        ;; see bug 256617
+        (js2-report-error "msg.bad.throw.eol"))
+    (setq expr (js2-parse-expr)
+          pn (make-js2-throw-node :pos pos
+                                  :len (- (js2-node-end expr) pos)
+                                  :expr expr))
+    (js2-node-add-children pn expr)
+    pn))
+
+(defsubst js2-match-jump-label-name (label-name)
+  "If break/continue specified a label, return that label's labeled stmt.
+Returns the corresponding `js2-labeled-stmt-node', or if LABEL-NAME
+does not match an existing label, reports an error and returns nil."
+  (let ((bundle (cdr (assoc label-name js2-label-set))))
+    (if (null bundle)
+        (js2-report-error "msg.undef.label"))
+    bundle))
+
+(defun js2-parse-break ()
+  "Parser for break-statement.  Last matched token must be js2-BREAK."
+  (let ((pos js2-token-beg)
+        (end js2-token-end)
+        break-target ; statement to break from
+        break-label  ; in "break foo", name-node representing the foo
+        labels       ; matching labeled statement to break to
+        pn)
+    (js2-consume-token)  ; `break'
+    (when (eq (js2-peek-token-or-eol) js2-NAME)
+      (js2-consume-token)
+      (setq break-label (js2-create-name-node)
+            end (js2-node-end break-label)
+            ;; matchJumpLabelName only matches if there is one
+            labels (js2-match-jump-label-name js2-ts-string)
+            break-target (if labels (car (js2-labeled-stmt-node-labels 
labels)))))
+    (unless (or break-target break-label)
+      ;; no break target specified - try for innermost enclosing loop/switch
+      (if (null js2-loop-and-switch-set)
+          (unless break-label
+            (js2-report-error "msg.bad.break" nil pos (length "break")))
+        (setq break-target (car js2-loop-and-switch-set))))
+    (setq pn (make-js2-break-node :pos pos
+                                  :len (- end pos)
+                                  :label break-label
+                                  :target break-target))
+    (js2-node-add-children pn break-label)  ; but not break-target
+    pn))
+
+(defun js2-parse-continue ()
+  "Parser for continue-statement.  Last matched token must be js2-CONTINUE."
+  (let ((pos js2-token-beg)
+        (end js2-token-end)
+        label   ; optional user-specified label, a `js2-name-node'
+        labels  ; current matching labeled stmt, if any
+        target  ; the `js2-loop-node' target of this continue stmt
+        pn)
+    (js2-consume-token)  ; `continue'
+    (when (= (js2-peek-token-or-eol) js2-NAME)
+      (js2-consume-token)
+      (setq label (js2-create-name-node)
+            end (js2-node-end label)
+            ;; matchJumpLabelName only matches if there is one
+            labels (js2-match-jump-label-name js2-ts-string)))
+    (cond
+     ((null labels)  ; no current label to go to
+      (if (null js2-loop-set)  ; no loop to continue to
+          (js2-report-error "msg.continue.outside" nil pos
+                            (length "continue"))
+        (setq target (car js2-loop-set))))  ; innermost enclosing loop
+     (t
+      (if (js2-loop-node-p (js2-labeled-stmt-node-stmt labels))
+          (setq target (js2-labeled-stmt-node-stmt labels))
+        (js2-report-error "msg.continue.nonloop" nil pos (- end pos)))))
+    (setq pn (make-js2-continue-node :pos pos
+                                     :len (- end pos)
+                                     :label label
+                                     :target target))
+    (js2-node-add-children pn label)  ; but not target - it's not our child
+    pn))
+
+(defun js2-parse-with ()
+  "Parser for with-statement.  Last matched token must be js2-WITH."
+  (js2-consume-token)
+  (let ((pos js2-token-beg)
+        obj body pn lp rp)
+    (if (js2-must-match js2-LP "msg.no.paren.with")
+        (setq lp js2-token-beg))
+    (setq obj (js2-parse-expr))
+    (if (js2-must-match js2-RP "msg.no.paren.after.with")
+        (setq rp js2-token-beg))
+    (let ((js2-nesting-of-with (1+ js2-nesting-of-with)))
+        (setq body (js2-parse-statement)))
+    (setq pn (make-js2-with-node :pos pos
+                                 :len (- (js2-node-end body) pos)
+                                 :object obj
+                                 :body body
+                                 :lp (js2-relpos lp pos)
+                                 :rp (js2-relpos rp pos)))
+    (js2-node-add-children pn obj body)
+    pn))
+
+(defun js2-parse-const-var ()
+  "Parser for var- or const-statement.
+Last matched token must be js2-CONST or js2-VAR."
+  (let ((tt (js2-peek-token))
+        (pos js2-token-beg)
+        expr
+        pn)
+    (js2-consume-token)
+    (setq expr (js2-parse-variables tt js2-token-beg)
+          pn (make-js2-expr-stmt-node :pos pos
+                                      :len (- (js2-node-end expr) pos)
+                                      :expr expr))
+    (js2-node-add-children pn expr)
+    pn))
+
+(defsubst js2-wrap-with-expr-stmt (pos expr &optional add-child)
+  (let ((pn (make-js2-expr-stmt-node :pos pos
+                                     :len (js2-node-len expr)
+                                     :type (if (js2-inside-function)
+                                               js2-EXPR_VOID
+                                             js2-EXPR_RESULT)
+                                     :expr expr)))
+    (if add-child
+        (js2-node-add-children pn expr))
+    pn))
+
+(defun js2-parse-let-stmt ()
+  "Parser for let-statement.  Last matched token must be js2-LET."
+  (js2-consume-token)
+  (let ((pos js2-token-beg)
+        expr
+        pn)
+    (if (= (js2-peek-token) js2-LP)
+        ;; let expression in statement context
+        (setq expr (js2-parse-let pos 'statement)
+              pn (js2-wrap-with-expr-stmt pos expr t))
+      ;; else we're looking at a statement like let x=6, y=7;
+      (setf expr (js2-parse-variables js2-LET pos)
+            pn (js2-wrap-with-expr-stmt pos expr t)
+            (js2-node-type pn) js2-EXPR_RESULT))
+    pn))
+
+(defun js2-parse-ret-yield ()
+  (js2-parse-return-or-yield (js2-peek-token) nil))
+
+(defconst js2-parse-return-stmt-enders
+  (list js2-SEMI js2-RC js2-EOF js2-EOL js2-ERROR js2-RB js2-RP js2-YIELD))
+
+(defsubst js2-now-all-set (before after mask)
+  "Return whether or not the bits in the mask have changed to all set.
+BEFORE is bits before change, AFTER is bits after change, and MASK is
+the mask for bits.  Returns t if all the bits in the mask are set in AFTER
+but not BEFORE."
+  (and (/= (logand before mask) mask)
+       (= (logand after mask) mask)))
+
+(defun js2-parse-return-or-yield (tt expr-context)
+  (let ((pos js2-token-beg)
+        (end js2-token-end)
+        (before js2-end-flags)
+        (inside-function (js2-inside-function))
+        e
+        ret
+        name)
+    (unless inside-function
+      (js2-report-error (if (eq tt js2-RETURN)
+                            "msg.bad.return"
+                          "msg.bad.yield")))
+    (js2-consume-token)
+    ;; This is ugly, but we don't want to require a semicolon.
+    (unless (memq (js2-peek-token-or-eol) js2-parse-return-stmt-enders)
+      (setq e (js2-parse-expr)
+            end (js2-node-end e)))
+    (cond
+     ((eq tt js2-RETURN)
+      (js2-set-flag js2-end-flags (if (null e)
+                                      js2-end-returns
+                                    js2-end-returns-value))
+      (setq ret (make-js2-return-node :pos pos
+                                      :len (- end pos)
+                                      :retval e))
+      (js2-node-add-children ret e)
+      ;; See if we need a strict mode warning.
+      ;; TODO:  The analysis done by `js2-has-consistent-return-usage' is
+      ;; more thorough and accurate than this before/after flag check.
+      ;; E.g. if there's a finally-block that always returns, we shouldn't
+      ;; show a warning generated by inconsistent returns in the catch blocks.
+      ;; Basically `js2-has-consistent-return-usage' needs to keep more state,
+      ;; so we know which returns/yields to highlight, and we should get rid of
+      ;; all the checking in `js2-parse-return-or-yield'.
+      (if (and js2-strict-inconsistent-return-warning
+               (js2-now-all-set before js2-end-flags
+                                (logior js2-end-returns 
js2-end-returns-value)))
+          (js2-add-strict-warning "msg.return.inconsistent" nil pos end)))
+     (t
+      (unless (js2-inside-function)
+        (js2-report-error "msg.bad.yield"))
+      (js2-set-flag js2-end-flags js2-end-yields)
+      (setq ret (make-js2-yield-node :pos pos
+                                     :len (- end pos)
+                                     :value e))
+      (js2-node-add-children ret e)
+      (unless expr-context
+        (setq e ret
+              ret (js2-wrap-with-expr-stmt pos e t))
+      (js2-set-requires-activation)
+      (js2-set-is-generator))))
+    ;; see if we are mixing yields and value returns.
+    (when (and inside-function
+               (js2-now-all-set before js2-end-flags
+                                (logior js2-end-yields js2-end-returns-value)))
+      (setq name (js2-function-name js2-current-script-or-fn))
+      (if (zerop (length name))
+          (js2-report-error "msg.anon.generator.returns" nil pos (- end pos))
+        (js2-report-error "msg.generator.returns" name pos (- end pos))))
+    ret))
+
+(defun js2-parse-debugger ()
+  (js2-consume-token)
+  (make-js2-keyword-node :type js2-DEBUGGER))
+
+(defun js2-parse-block ()
+  "Parser for a curly-delimited statement block.
+Last token matched must be js2-LC."
+  (let ((pos js2-token-beg)
+        (pn (make-js2-scope)))
+    (js2-consume-token)
+    (js2-push-scope pn)
+    (unwind-protect
+        (progn
+          (js2-parse-statements pn)
+          (js2-must-match js2-RC "msg.no.brace.block")
+          (setf (js2-node-len pn) (- js2-token-end pos)))
+      (js2-pop-scope))
+    pn))
+
+;; for js2-ERROR too, to have a node for error recovery to work on
+(defun js2-parse-semi ()
+  "Parse a statement or handle an error.
+Last matched token is js-SEMI or js-ERROR."
+  (let ((tt (js2-peek-token)) pos len)
+    (js2-consume-token)
+    (if (eq tt js2-SEMI)
+        (make-js2-empty-expr-node :len 1)
+      (setq pos js2-token-beg
+            len (- js2-token-beg pos))
+      (js2-report-error "msg.syntax" nil pos len)
+      (make-js2-error-node :pos pos :len len))))
+
+(defun js2-parse-default-xml-namespace ()
+  "Parse a `default xml namespace = <expr>' e4x statement."
+  (let ((pos js2-token-beg)
+        end len expr unary es)
+    (js2-consume-token)
+    (js2-must-have-xml)
+    (js2-set-requires-activation)
+    (setq len (- js2-ts-cursor pos))
+    (unless (and (js2-match-token js2-NAME)
+                 (string= js2-ts-string "xml"))
+      (js2-report-error "msg.bad.namespace" nil pos len))
+    (unless (and (js2-match-token js2-NAME)
+                 (string= js2-ts-string "namespace"))
+      (js2-report-error "msg.bad.namespace" nil pos len))
+    (unless (js2-match-token js2-ASSIGN)
+      (js2-report-error "msg.bad.namespace" nil pos len))
+    (setq expr (js2-parse-expr)
+          end (js2-node-end expr)
+          unary (make-js2-unary-node :type js2-DEFAULTNAMESPACE
+                                     :pos pos
+                                     :len (- end pos)
+                                     :operand expr))
+    (js2-node-add-children unary expr)
+    (make-js2-expr-stmt-node :pos pos
+                             :len (- end pos)
+                             :expr unary)))
+
+(defun js2-record-label (label bundle)
+  ;; current token should be colon that `js2-parse-primary-expr' left untouched
+  (js2-consume-token)
+  (let ((name (js2-label-node-name label))
+        labeled-stmt
+        dup)
+    (when (setq labeled-stmt (cdr (assoc name js2-label-set)))
+      ;; flag both labels if possible when used in editing mode
+      (if (and js2-parse-ide-mode
+               (setq dup (js2-get-label-by-name labeled-stmt name)))
+          (js2-report-error "msg.dup.label" nil
+                            (js2-node-abs-pos dup) (js2-node-len dup)))
+      (js2-report-error "msg.dup.label" nil
+                        (js2-node-pos label) (js2-node-len label)))
+    (js2-labeled-stmt-node-add-label bundle label)
+    (js2-node-add-children bundle label)
+    ;; Add one reference to the bundle per label in `js2-label-set'
+    (push (cons name bundle) js2-label-set)))
+
+(defun js2-parse-name-or-label ()
+  "Parser for identifier or label.  Last token matched must be js2-NAME.
+Called when we found a name in a statement context.  If it's a label, we gather
+up any following labels and the next non-label statement into a
+`js2-labeled-stmt-node' bundle and return that.  Otherwise we parse an
+expression and return it wrapped in a `js2-expr-stmt-node'."
+  (let ((pos js2-token-beg)
+        (end js2-token-end)
+        expr
+        stmt
+        pn
+        bundle
+        (continue t))
+    ;; set check for label and call down to `js2-parse-primary-expr'
+    (js2-set-check-for-label)
+    (setq expr (js2-parse-expr))
+    (if (/= (js2-node-type expr) js2-LABEL)
+        ;; Parsed non-label expression - wrap with expression stmt.
+        (setq pn (js2-wrap-with-expr-stmt pos expr t))
+      ;; else parsed a label
+      (setq bundle (make-js2-labeled-stmt-node :pos pos))
+      (js2-record-label expr bundle)
+      ;; look for more labels
+      (while (and continue (= (js2-peek-token) js2-NAME))
+        (js2-set-check-for-label)
+        (setq expr (js2-parse-expr))
+        (if (/= (js2-node-type expr) js2-LABEL)
+            (progn
+              (setq stmt (js2-wrap-with-expr-stmt (js2-node-pos expr) expr t)
+                    continue nil)
+              (js2-auto-insert-semicolon stmt))
+          (js2-record-label expr bundle)))
+      ;; no more labels; now parse the labeled statement
+      (unwind-protect
+            (unless stmt
+              (let ((js2-labeled-stmt bundle))  ; bind dynamically
+                (setq stmt (js2-statement-helper))))
+        ;; remove the labels for this statement from the global set
+        (dolist (label (js2-labeled-stmt-node-labels bundle))
+          (setq js2-label-set (remove label js2-label-set))))
+      (setf (js2-labeled-stmt-node-stmt bundle) stmt
+            (js2-node-len bundle) (- (js2-node-end stmt) pos))
+      (js2-node-add-children bundle stmt)
+      bundle)))
+
+(defun js2-parse-expr-stmt ()
+  "Default parser in statement context, if no recognized statement found."
+  (js2-wrap-with-expr-stmt js2-token-beg (js2-parse-expr) t))
+
+(defun js2-parse-variables (decl-type pos)
+  "Parse a comma-separated list of variable declarations.
+Could be a 'var', 'const' or 'let' expression, possibly in a for-loop 
initializer.
+
+DECL-TYPE is a token value: either VAR, CONST, or LET depending on context.
+For 'var' or 'const', the keyword should be the token last scanned.
+
+POS is the position where the node should start. It's sometimes the
+var/const/let keyword, and other times the beginning of the first token
+in the first variable declaration.
+
+Returns the parsed `js2-var-decl-node' expression node."
+  (let* ((result (make-js2-var-decl-node :decl-type decl-type
+                                         :pos pos))
+         destructuring
+         kid-pos
+         tt
+         init
+         name
+         end
+         nbeg nend
+         vi
+         (continue t))
+    ;; Example:
+    ;; var foo = {a: 1, b: 2}, bar = [3, 4];
+    ;; var {b: s2, a: s1} = foo, x = 6, y, [s3, s4] = bar;
+    (while continue
+      (setq destructuring nil
+            name nil
+            tt (js2-peek-token)
+            kid-pos js2-token-beg
+            end js2-token-end
+            init nil)
+      (if (or (= tt js2-LB) (= tt js2-LC))
+          ;; Destructuring assignment, e.g., var [a, b] = ...
+          (setq destructuring (js2-parse-primary-expr)
+                end (js2-node-end destructuring))
+        ;; Simple variable name
+        (when (js2-must-match js2-NAME "msg.bad.var")
+          (setq name (js2-create-name-node)
+                nbeg js2-token-beg
+                nend js2-token-end
+                end nend)
+          (js2-define-symbol decl-type js2-ts-string name js2-in-for-init)))
+      (when (js2-match-token js2-ASSIGN)
+        (setq init (js2-parse-assign-expr)
+              end (js2-node-end init))
+        (if (and js2-parse-ide-mode
+                 (or (js2-object-node-p init)
+                     (js2-function-node-p init)))
+            (js2-record-imenu-functions init name)))
+      (when name
+        (js2-set-face nbeg nend (if (js2-function-node-p init)
+                                    'font-lock-function-name-face
+                                  'font-lock-variable-name-face)
+                      'record))
+      (setq vi (make-js2-var-init-node :pos kid-pos
+                                       :len (- end kid-pos)
+                                       :type decl-type))
+      (if destructuring
+          (progn
+            (if (and (null init) (not js2-in-for-init))
+                (js2-report-error "msg.destruct.assign.no.init"))
+            (setf (js2-var-init-node-target vi) destructuring))
+        (setf (js2-var-init-node-target vi) name))
+      (setf (js2-var-init-node-initializer vi) init)
+      (js2-node-add-children vi name destructuring init)
+      (js2-block-node-push result vi)
+      (unless (js2-match-token js2-COMMA)
+        (setq continue nil)))
+    (setf (js2-node-len result) (- end pos))
+    result))
+
+(defun js2-parse-let (pos &optional stmt-p)
+  "Parse a let expression or statement.
+A let-expression is of the form `let (vars) expr'.
+A let-statment is of the form `let (vars) {statements}'.
+The third form of let is a variable declaration list, handled
+by `js2-parse-variables'."
+  (let ((pn (make-js2-let-node :pos pos))
+        beg vars body)
+    (if (js2-must-match js2-LP "msg.no.paren.after.let")
+        (setf (js2-let-node-lp pn) (- js2-token-beg pos)))
+    (js2-push-scope pn)
+    (unwind-protect
+        (progn
+          (setq vars (js2-parse-variables js2-LET js2-token-beg))
+          (if (js2-must-match js2-RP "msg.no.paren.let")
+              (setf (js2-let-node-rp pn) (- js2-token-beg pos)))
+          (if (and stmt-p (eq (js2-peek-token) js2-LC))
+              ;; let statement
+              (progn
+                (js2-consume-token)
+                (setf beg js2-token-beg  ; position stmt at LC
+                      body (js2-parse-statements))
+                (js2-must-match js2-RC "msg.no.curly.let")
+                (setf (js2-node-len body) (- js2-token-end beg)
+                      (js2-node-len pn) (- js2-token-end pos)
+                      (js2-let-node-body pn) body
+                      (js2-node-type pn) js2-LET))
+            ;; let expression
+            (setf body (js2-parse-expr)
+                  (js2-node-len pn) (- (js2-node-end body) pos)
+                  (js2-let-node-body pn) body))
+          (js2-node-add-children pn vars body))
+      (js2-pop-scope))
+    pn))
+
+(defsubst js2-define-new-symbol (decl-type name node)
+  (js2-scope-put-symbol js2-current-scope
+                        name
+                        (make-js2-symbol decl-type name node)))
+
+(defun js2-define-symbol (decl-type name &optional node ignore-not-in-block)
+  "Define a symbol in the current scope.
+If NODE is non-nil, it is the AST node associated with the symbol."
+  (let* ((defining-scope (js2-get-defining-scope js2-current-scope name))
+         (symbol (if defining-scope
+                     (js2-scope-get-symbol defining-scope name)))
+         (sdt (if symbol (js2-symbol-decl-type symbol) -1)))
+    (cond
+     ((and symbol ; already defined
+           (or (= sdt js2-CONST) ; old version is const
+               (= decl-type js2-CONST) ; new version is const
+               ;; two let-bound vars in this block have same name
+               (and (= sdt js2-LET)
+                    (eq defining-scope js2-current-scope))))
+      (js2-report-error
+       (cond
+        ((= sdt js2-CONST) "msg.const.redecl")
+        ((= sdt js2-LET) "msg.let.redecl")
+        ((= sdt js2-VAR) "msg.var.redecl")
+        ((= sdt js2-FUNCTION) "msg.function.redecl")
+        (t "msg.parm.redecl"))
+       name))
+     ((= decl-type js2-LET)
+      (if (and (not ignore-not-in-block)
+               (or (= (js2-node-type js2-current-scope) js2-IF)
+                   (js2-loop-node-p js2-current-scope)))
+          (js2-report-error "msg.let.decl.not.in.block")
+        (js2-define-new-symbol decl-type name node)))
+     ((or (= decl-type js2-VAR)
+          (= decl-type js2-CONST)
+          (= decl-type js2-FUNCTION))
+      (if symbol
+          (if (and js2-strict-var-redeclaration-warning (= sdt js2-VAR))
+              (js2-add-strict-warning "msg.var.redecl" name)
+            (if (and js2-strict-var-hides-function-arg-warning (= sdt js2-LP))
+                (js2-add-strict-warning "msg.var.hides.arg" name)))
+        (js2-define-new-symbol decl-type name node)))
+     ((= decl-type js2-LP)
+      (if symbol
+          ;; must be duplicate parameter. Second parameter hides the
+          ;; first, so go ahead and add the second pararameter
+          (js2-report-warning "msg.dup.parms" name))
+      (js2-define-new-symbol decl-type name node))
+     (t (js2-code-bug)))))
+
+(defun js2-parse-expr ()
+  (let* ((pn (js2-parse-assign-expr))
+         (pos (js2-node-pos pn))
+         left
+         right
+         op-pos)
+    (while (js2-match-token js2-COMMA)
+      (setq op-pos (- js2-token-beg pos))  ; relative
+      (if (= (js2-peek-token) js2-YIELD)
+          (js2-report-error "msg.yield.parenthesized"))
+      (setq right (js2-parse-assign-expr)
+            left pn
+            pn (make-js2-infix-node :type js2-COMMA
+                                    :pos pos
+                                    :len (- js2-ts-cursor pos)
+                                    :op-pos op-pos
+                                    :left left
+                                    :right right))
+      (js2-node-add-children pn left right))
+    pn))
+
+(defun js2-parse-assign-expr ()
+  (let ((tt (js2-peek-token))
+        (pos js2-token-beg)
+        pn
+        left
+        right
+        op-pos)
+    (if (= tt js2-YIELD)
+        (js2-parse-return-or-yield tt t)
+      ;; not yield - parse assignment expression
+      (setq pn (js2-parse-cond-expr)
+            tt (js2-peek-token))
+      (when (and (<= js2-first-assign tt)
+                 (<= tt js2-last-assign))
+        (js2-consume-token)
+        (setq op-pos (- js2-token-beg pos)  ; relative
+              left pn
+              right (js2-parse-assign-expr)
+              pn (make-js2-assign-node :type tt
+                                       :pos pos
+                                       :len (- (js2-node-end right) pos)
+                                       :op-pos op-pos
+                                       :left left
+                                       :right right))
+        (when js2-parse-ide-mode
+          (js2-highlight-assign-targets pn left right)
+          (if (or (js2-function-node-p right)
+                  (js2-object-node-p right))
+              (js2-record-imenu-functions right left)))
+        ;; do this last so ide checks above can use absolute positions
+        (js2-node-add-children pn left right))
+      pn)))
+
+(defun js2-parse-cond-expr ()
+  (let ((pos js2-token-beg)
+        (pn (js2-parse-or-expr))
+        test-expr
+        if-true
+        if-false
+        q-pos
+        c-pos)
+    (when (js2-match-token js2-HOOK)
+      (setq q-pos (- js2-token-beg pos)
+            if-true (js2-parse-assign-expr))
+      (js2-must-match js2-COLON "msg.no.colon.cond")
+      (setq c-pos (- js2-token-beg pos)
+            if-false (js2-parse-assign-expr)
+            test-expr pn
+            pn (make-js2-cond-node :pos pos
+                                   :len (- (js2-node-end if-false) pos)
+                                   :test-expr test-expr
+                                   :true-expr if-true
+                                   :false-expr if-false
+                                   :q-pos q-pos
+                                   :c-pos c-pos))
+      (js2-node-add-children pn test-expr if-true if-false))
+    pn))
+
+(defun js2-make-binary (type left parser)
+  "Helper for constructing a binary-operator AST node.
+LEFT is the left-side-expression, already parsed, and the
+binary operator should have just been matched.
+PARSER is a function to call to parse the right operand,
+or a `js2-node' struct if it has already been parsed."
+  (let* ((pos (js2-node-pos left))
+         (op-pos (- js2-token-beg pos))
+         (right (if (js2-node-p parser)
+                    parser
+                  (funcall parser)))
+         (pn (make-js2-infix-node :type type
+                                  :pos pos
+                                  :len (- (js2-node-end right) pos)
+                                  :op-pos op-pos
+                                  :left left
+                                  :right right)))
+    (js2-node-add-children pn left right)
+    pn))
+
+(defun js2-parse-or-expr ()
+  (let ((pn (js2-parse-and-expr)))
+    (when (js2-match-token js2-OR)
+      (setq pn (js2-make-binary js2-OR
+                                pn
+                                'js2-parse-or-expr)))
+    pn))
+
+(defun js2-parse-and-expr ()
+  (let ((pn (js2-parse-bit-or-expr)))
+    (when (js2-match-token js2-AND)
+      (setq pn (js2-make-binary js2-AND
+                                pn
+                                'js2-parse-and-expr)))
+    pn))
+
+(defun js2-parse-bit-or-expr ()
+  (let ((pn (js2-parse-bit-xor-expr)))
+    (while (js2-match-token js2-BITOR)
+      (setq pn (js2-make-binary js2-BITOR
+                                pn
+                                'js2-parse-bit-xor-expr)))
+    pn))
+
+(defun js2-parse-bit-xor-expr ()
+  (let ((pn (js2-parse-bit-and-expr)))
+    (while (js2-match-token js2-BITXOR)
+      (setq pn (js2-make-binary js2-BITXOR
+                                pn
+                                'js2-parse-bit-and-expr)))
+    pn))
+
+(defun js2-parse-bit-and-expr ()
+  (let ((pn (js2-parse-eq-expr)))
+    (while (js2-match-token js2-BITAND)
+      (setq pn (js2-make-binary js2-BITAND
+                                pn
+                                'js2-parse-eq-expr)))
+    pn))
+
+(defconst js2-parse-eq-ops
+  (list js2-EQ js2-NE js2-SHEQ js2-SHNE))
+
+(defun js2-parse-eq-expr ()
+  (let ((pn (js2-parse-rel-expr))
+        tt)
+    (while (memq (setq tt (js2-peek-token)) js2-parse-eq-ops)
+      (js2-consume-token)
+      (setq pn (js2-make-binary tt
+                                pn
+                                'js2-parse-rel-expr)))
+    pn))
+
+(defconst js2-parse-rel-ops
+  (list js2-IN js2-INSTANCEOF js2-LE js2-LT js2-GE js2-GT))
+
+(defun js2-parse-rel-expr ()
+  (let ((pn (js2-parse-shift-expr))
+        (continue t)
+        tt)
+    (while continue
+      (setq tt (js2-peek-token))
+      (cond
+       ((and js2-in-for-init (= tt js2-IN))
+        (setq continue nil))
+       ((memq tt js2-parse-rel-ops)
+        (js2-consume-token)
+        (setq pn (js2-make-binary tt pn 'js2-parse-shift-expr)))
+       (t
+        (setq continue nil))))
+    pn))
+
+(defconst js2-parse-shift-ops
+  (list js2-LSH js2-URSH js2-RSH))
+
+(defun js2-parse-shift-expr ()
+  (let ((pn (js2-parse-add-expr))
+        tt
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (if (memq tt js2-parse-shift-ops)
+          (progn
+            (js2-consume-token)
+            (setq pn (js2-make-binary tt pn 'js2-parse-add-expr)))
+        (setq continue nil)))
+    pn))
+
+(defun js2-parse-add-expr ()
+  (let ((pn (js2-parse-mul-expr))
+        tt
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (if (or (= tt js2-ADD) (= tt js2-SUB))
+          (progn
+            (js2-consume-token)
+            (setq pn (js2-make-binary tt pn 'js2-parse-mul-expr)))
+        (setq continue nil)))
+    pn))
+
+(defconst js2-parse-mul-ops
+  (list js2-MUL js2-DIV js2-MOD))
+
+(defun js2-parse-mul-expr ()
+  (let ((pn (js2-parse-unary-expr))
+        tt
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (if (memq tt js2-parse-mul-ops)
+          (progn
+            (js2-consume-token)
+            (setq pn (js2-make-binary tt pn 'js2-parse-unary-expr)))
+        (setq continue nil)))
+    pn))
+
+(defsubst js2-make-unary (type parser &rest args)
+  "Make a unary node of type TYPE.
+PARSER is either a node (for postfix operators) or a function to call
+to parse the operand (for prefix operators)."
+  (let* ((pos js2-token-beg)
+         (postfix (js2-node-p parser))
+         (expr (if postfix
+                   parser
+                 (apply parser args)))
+         end
+         pn)
+    (if postfix  ; e.g. i++
+        (setq pos (js2-node-pos expr)
+              end js2-token-end)
+      (setq end (js2-node-end expr)))
+    (setq pn (make-js2-unary-node :type type
+                                  :pos pos
+                                  :len (- end pos)
+                                  :operand expr))
+    (js2-node-add-children pn expr)
+    pn))
+
+(defconst js2-incrementable-node-types
+  (list js2-NAME js2-GETPROP js2-GETELEM js2-GET_REF js2-CALL)
+  "Node types that can be the operand of a ++ or -- operator.")
+
+(defsubst js2-check-bad-inc-dec (tt beg end unary)
+  (unless (memq (js2-node-type (js2-unary-node-operand unary))
+                js2-incrementable-node-types)
+    (js2-report-error (if (= tt js2-INC)
+                          "msg.bad.incr"
+                        "msg.bad.decr")
+                      nil beg (- end beg))))
+
+(defun js2-parse-unary-expr ()
+  (let ((tt (js2-peek-token))
+        pn expr beg end)
+    (cond
+     ((or (= tt js2-VOID)
+          (= tt js2-NOT)
+          (= tt js2-BITNOT)
+          (= tt js2-TYPEOF))
+      (js2-consume-token)
+      (js2-make-unary tt 'js2-parse-unary-expr))
+     ((= tt js2-ADD)
+      (js2-consume-token)
+      ;; Convert to special POS token in decompiler and parse tree
+      (js2-make-unary js2-POS 'js2-parse-unary-expr))
+     ((= tt js2-SUB)
+      (js2-consume-token)
+      ;; Convert to special NEG token in decompiler and parse tree
+      (js2-make-unary js2-NEG 'js2-parse-unary-expr))
+     ((or (= tt js2-INC)
+          (= tt js2-DEC))
+      (js2-consume-token)
+      (prog1
+          (setq beg js2-token-beg
+                end js2-token-end
+                expr (js2-make-unary tt 'js2-parse-member-expr t))
+        (js2-check-bad-inc-dec tt beg end expr)))
+     ((= tt js2-DELPROP)
+      (js2-consume-token)
+      (js2-make-unary js2-DELPROP 'js2-parse-unary-expr))
+     ((= tt js2-ERROR)
+      (js2-consume-token)
+      (make-js2-error-node))  ; try to continue
+     ((and (= tt js2-LT)
+           js2-compiler-xml-available)
+      ;; XML stream encountered in expression.
+      (js2-consume-token)
+      (js2-parse-member-expr-tail t (js2-parse-xml-initializer)))
+     (t
+      (setq pn (js2-parse-member-expr t)
+            ;; Don't look across a newline boundary for a postfix incop.
+            tt (js2-peek-token-or-eol))
+      (when (or (= tt js2-INC) (= tt js2-DEC))
+        (js2-consume-token)
+        (setf expr pn
+              pn (js2-make-unary tt expr))
+        (js2-node-set-prop pn 'postfix t)
+        (js2-check-bad-inc-dec tt js2-token-beg js2-token-end pn))
+      pn))))
+
+(defun js2-parse-xml-initializer ()
+  "Parse an E4X XML initializer.
+I'm parsing it the way Rhino parses it, but without the tree-rewriting.
+Then I'll postprocess the result, depending on whether we're in IDE
+mode or codegen mode, and generate the appropriate rewritten AST.
+IDE mode uses a rich AST that models the XML structure.  Codegen mode
+just concatenates everything and makes a new XML or XMLList out of it."
+  (let ((tt (js2-get-first-xml-token))
+        pn-xml
+        pn
+        expr
+        kids
+        expr-pos
+        (continue t)
+        (first-token t))
+    (when (not (or (= tt js2-XML) (= tt js2-XMLEND)))
+      (js2-report-error "msg.syntax"))
+    (setq pn-xml (make-js2-xml-node))
+    (while continue
+      (if first-token
+          (setq first-token nil)
+        (setq tt (js2-get-next-xml-token)))
+      (cond
+       ;; js2-XML means we found a {expr} in the XML stream.
+       ;; The js2-ts-string is the XML up to the left-curly.
+       ((= tt js2-XML)
+        (push (make-js2-string-node :pos js2-token-beg
+                                    :len (- js2-ts-cursor js2-token-beg))
+              kids)
+        (js2-must-match js2-LC "msg.syntax")
+        (setq expr-pos js2-ts-cursor
+              expr (if (eq (js2-peek-token) js2-RC)
+                       (make-js2-empty-expr-node :pos expr-pos)
+                     (js2-parse-expr)))
+        (js2-must-match js2-RC "msg.syntax")
+        (setq pn (make-js2-xml-js-expr-node :pos (js2-node-pos expr)
+                                            :len (js2-node-len expr)
+                                            :expr expr))
+        (js2-node-add-children pn expr)
+        (push pn kids))
+       ;; a js2-XMLEND token means we hit the final close-tag.
+       ((= tt js2-XMLEND)
+        (push (make-js2-string-node :pos js2-token-beg
+                                    :len (- js2-ts-cursor js2-token-beg))
+              kids)
+        (dolist (kid (nreverse kids))
+          (js2-block-node-push pn-xml kid))
+        (setf (js2-node-len pn-xml) (- js2-ts-cursor
+                                       (js2-node-pos pn-xml))
+              continue nil))
+       (t
+        (js2-report-error "msg.syntax")
+        (setq continue nil))))
+    pn-xml))
+
+
+(defun js2-parse-argument-list ()
+  "Parse an argument list and return it as a lisp list of nodes.
+Returns the list in reverse order.  Consumes the right-paren token."
+  (let (result)
+    (unless (js2-match-token js2-RP)
+      (loop do
+            (if (= (js2-peek-token) js2-YIELD)
+                (js2-report-error "msg.yield.parenthesized"))
+            (push (js2-parse-assign-expr) result)
+            while
+            (js2-match-token js2-COMMA))
+      (js2-must-match js2-RP "msg.no.paren.arg")
+      result)))
+
+(defun js2-parse-member-expr (&optional allow-call-syntax)
+  (let ((tt (js2-peek-token))
+        pn
+        pos
+        target
+        args
+        beg
+        end
+        init
+        tail)
+    (if (/= tt js2-NEW)
+        (setq pn (js2-parse-primary-expr))
+      ;; parse a 'new' expression
+      (js2-consume-token)
+      (setq pos js2-token-beg
+            beg pos
+            target (js2-parse-member-expr)
+            end (js2-node-end target)
+            pn (make-js2-new-node :pos pos
+                                  :target target
+                                  :len (- end pos)))
+      (js2-node-add-children pn target)
+      (when (js2-match-token js2-LP)
+        ;; Add the arguments to pn, if any are supplied.
+        (setf beg pos  ; start of "new" keyword
+              pos js2-token-beg
+              args (nreverse (js2-parse-argument-list))
+              (js2-new-node-args pn) args
+              end js2-token-end
+              (js2-new-node-lp pn) (- pos beg)
+              (js2-new-node-rp pn) (- end 1 beg))
+        (apply #'js2-node-add-children pn args))
+      (when (and js2-allow-rhino-new-expr-initializer
+                 (js2-match-token js2-LC))
+        (setf init (js2-parse-object-literal)
+              end (js2-node-end init)
+              (js2-new-node-initializer pn) init)
+        (js2-node-add-children pn init))
+        (setf (js2-node-len pn) (- end beg)))  ; end outer if
+    (js2-parse-member-expr-tail allow-call-syntax pn)))
+
+(defun js2-parse-member-expr-tail (allow-call-syntax pn)
+  "Parse a chain of property/array accesses or function calls.
+Includes parsing for E4X operators like `..' and `.@'.
+If ALLOW-CALL-SYNTAX is nil, stops when we encounter a left-paren.
+Returns an expression tree that includes PN, the parent node."
+  (let ((beg (js2-node-pos pn))
+        tt
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (cond
+       ((or (= tt js2-DOT) (= tt js2-DOTDOT))
+        (setq pn (js2-parse-property-access tt pn)))
+       ((= tt js2-DOTQUERY)
+        (setq pn (js2-parse-dot-query pn)))
+       ((= tt js2-LB)
+        (setq pn (js2-parse-element-get pn)))
+       ((= tt js2-LP)
+        (if allow-call-syntax
+            (setq pn (js2-parse-function-call pn))
+          (setq continue nil)))
+       (t
+        (setq continue nil))))
+    (if (>= js2-highlight-level 2)
+        (js2-parse-highlight-member-expr-node pn))
+    pn))
+
+(defun js2-parse-dot-query (pn)
+  "Parse a dot-query expression, e.g. foo.bar.(@name == 2)
+Last token parsed must be `js2-DOTQUERY'."
+  (let ((pos (js2-node-pos pn))
+        op-pos
+        expr
+        end)
+    (js2-consume-token)
+    (js2-must-have-xml)
+    (js2-set-requires-activation)
+    (setq op-pos js2-token-beg
+          expr (js2-parse-expr)
+          end (js2-node-end expr)
+          pn (make-js2-xml-dot-query-node :left pn
+                                          :pos pos
+                                          :op-pos op-pos
+                                          :right expr))
+    (js2-node-add-children pn
+                           (js2-xml-dot-query-node-left pn)
+                           (js2-xml-dot-query-node-right pn))
+    (if (js2-must-match js2-RP "msg.no.paren")
+        (setf (js2-xml-dot-query-node-rp pn) js2-token-beg
+              end js2-token-end))
+    (setf (js2-node-len pn) (- end pos))
+    pn))
+
+(defun js2-parse-element-get (pn)
+  "Parse an element-get expression, e.g. foo[bar].
+Last token parsed must be `js2-RB'."
+  (let ((lb js2-token-beg)
+        (pos (js2-node-pos pn))
+        rb
+        expr)
+    (js2-consume-token)
+    (setq expr (js2-parse-expr))
+    (if (js2-must-match js2-RB "msg.no.bracket.index")
+        (setq rb js2-token-beg))
+    (setq pn (make-js2-elem-get-node :target pn
+                                     :pos pos
+                                     :element expr
+                                     :lb (js2-relpos lb pos)
+                                     :rb (js2-relpos rb pos)
+                                     :len (- js2-token-end pos)))
+    (js2-node-add-children pn
+                           (js2-elem-get-node-target pn)
+                           (js2-elem-get-node-element pn))
+    pn))
+
+(defun js2-parse-function-call (pn)
+  (let (args
+        (pos (js2-node-pos pn)))
+    (js2-consume-token)
+    (setq pn (make-js2-call-node :pos pos
+                                 :target pn
+                                 :lp (- js2-token-beg pos)))
+    (js2-node-add-children pn (js2-call-node-target pn))
+    ;; Add the arguments to pn, if any are supplied.
+    (setf args (nreverse (js2-parse-argument-list))
+          (js2-call-node-rp pn) (- js2-token-beg pos)
+          (js2-call-node-args pn) args)
+    (apply #'js2-node-add-children pn args)
+    (setf (js2-node-len pn) (- js2-ts-cursor pos))
+    pn))
+
+(defun js2-parse-property-access (tt pn)
+  "Parse a property access, XML descendants access, or XML attr access."
+  (let ((member-type-flags 0)
+        (dot-pos js2-token-beg)
+        (dot-len (if (= tt js2-DOTDOT) 2 1))
+        name
+        ref  ; right side of . or .. operator
+        result)
+    (js2-consume-token)
+    (when (= tt js2-DOTDOT)
+      (js2-must-have-xml)
+      (setq member-type-flags js2-descendants-flag))
+    (if (not js2-compiler-xml-available)
+        (progn
+          (js2-must-match-prop-name "msg.no.name.after.dot")
+          (setq name (js2-create-name-node t js2-GETPROP)
+                result (make-js2-prop-get-node :left pn
+                                               :pos js2-token-beg
+                                               :right name
+                                               :len (- js2-token-end
+                                                       js2-token-beg)))
+          (js2-node-add-children result pn name)
+          result)
+      ;; otherwise look for XML operators
+      (setf result (if (= tt js2-DOT)
+                       (make-js2-prop-get-node)
+                     (make-js2-infix-node :type js2-DOTDOT))
+            (js2-node-pos result) (js2-node-pos pn)
+            (js2-infix-node-op-pos result) dot-pos
+            (js2-infix-node-left result) pn  ; do this after setting position
+            tt (js2-next-token))
+      (cond
+       ;; needed for generator.throw()
+       ((= tt js2-THROW)
+        (js2-save-name-token-data js2-token-beg "throw")
+        (setq ref (js2-parse-property-name nil js2-ts-string 
member-type-flags)))
+       ;; handles: name, ns::name, ns::*, ns::[expr]
+       ((js2-valid-prop-name-token tt)
+        (setq ref (js2-parse-property-name -1 js2-ts-string 
member-type-flags)))
+       ;; handles: *, *::name, *::*, *::[expr]
+       ((= tt js2-MUL)
+        (js2-save-name-token-data js2-token-beg "*")
+        (setq ref (js2-parse-property-name nil "*" member-type-flags)))
+       ;; handles: '@attr', '@ns::attr', '@ns::*', '@ns::[expr]', etc.
+       ((= tt js2-XMLATTR)
+        (setq result (js2-parse-attribute-access)))
+       (t
+        (js2-report-error "msg.no.name.after.dot" nil dot-pos dot-len)))
+      (if ref
+          (setf (js2-node-len result) (- (js2-node-end ref)
+                                         (js2-node-pos result))
+                (js2-infix-node-right result) ref))
+      (if (js2-infix-node-p result)
+          (js2-node-add-children result
+                                 (js2-infix-node-left result)
+                                 (js2-infix-node-right result)))
+      result)))
+
+(defun js2-parse-attribute-access ()
+  "Parse an E4X XML attribute expression.
+This includes expressions of the forms:
+
+  @attr      @ns::attr     @ns::*
+  @*         @*::attr      @*::*
+  @[expr]    @*::[expr]    @ns::[expr]
+
+Called if we peeked an '@' token."
+  (let ((tt (js2-next-token))
+        (at-pos js2-token-beg))
+    (cond
+     ;; handles: @name, @ns::name, @ns::*, @ns::[expr]
+     ((js2-valid-prop-name-token tt)
+      (js2-parse-property-name at-pos js2-ts-string 0))
+     ;; handles: @*, @*::name, @*::*, @*::[expr]
+     ((= tt js2-MUL)
+      (js2-save-name-token-data js2-token-beg "*")
+      (js2-parse-property-name js2-token-beg "*" 0))
+     ;; handles @[expr]
+     ((= tt js2-LB)
+      (js2-parse-xml-elem-ref at-pos))
+     (t
+      (js2-report-error "msg.no.name.after.xmlAttr")
+      ;; Avoid cascaded errors that happen if we make an error node here.
+      (js2-save-name-token-data js2-token-beg "")
+      (js2-parse-property-name js2-token-beg "" 0)))))
+
+(defun js2-parse-property-name (at-pos s member-type-flags)
+  "Check if :: follows name in which case it becomes qualified name.
+
+AT-POS is a natural number if we just read an '@' token, else nil.
+S is the name or string that was matched:  an identifier, 'throw' or '*'.
+MEMBER-TYPE-FLAGS is a bit set tracking whether we're a '.' or '..' child.
+
+Returns a `js2-xml-ref-node' if it's an attribute access, a child of a '..'
+operator, or the name is followed by ::.  For a plain name, returns a
+`js2-name-node'.  Returns a `js2-error-node' for malformed XML expressions."
+  (let ((pos (or at-pos js2-token-beg))
+        colon-pos
+        (name (js2-create-name-node t js2-current-token))
+        ns
+        tt
+        ref
+        pn)
+    (catch 'return
+      (when (js2-match-token js2-COLONCOLON)
+        (setq ns name
+              colon-pos js2-token-beg
+              tt (js2-next-token))
+        (cond
+         ;; handles name::name
+         ((js2-valid-prop-name-token tt)
+          (setq name (js2-create-name-node)))
+         ;; handles name::*
+         ((= tt js2-MUL)
+          (js2-save-name-token-data js2-token-beg "*")
+          (setq name (js2-create-name-node)))
+         ;; handles name::[expr]
+         ((= tt js2-LB)
+          (throw 'return (js2-parse-xml-elem-ref at-pos ns colon-pos)))
+         (t
+          (js2-report-error "msg.no.name.after.coloncolon"))))
+      (if (and (null ns) (zerop member-type-flags))
+          name
+        (prog1
+            (setq pn
+                  (make-js2-xml-prop-ref-node :pos pos
+                                              :len (- (js2-node-end name) pos)
+                                              :at-pos at-pos
+                                              :colon-pos colon-pos
+                                              :propname name))
+          (js2-node-add-children pn name))))))
+
+(defun js2-parse-xml-elem-ref (at-pos &optional namespace colon-pos)
+  "Parse the [expr] portion of an xml element reference.
+For instance, @[expr], @*::[expr], or ns::[expr]."
+  (let* ((lb js2-token-beg)
+         (pos (or at-pos lb))
+         rb
+         (expr (js2-parse-expr))
+         (end (js2-node-end expr))
+         pn)
+    (if (js2-must-match js2-RB "msg.no.bracket.index")
+        (setq rb js2-token-beg
+              end js2-token-end))
+    (prog1
+        (setq pn
+              (make-js2-xml-elem-ref-node :pos pos
+                                          :len (- end pos)
+                                          :namespace namespace
+                                          :colon-pos colon-pos
+                                          :at-pos at-pos
+                                          :expr expr
+                                          :lb (js2-relpos lb pos)
+                                          :rb (js2-relpos rb pos)))
+      (js2-node-add-children pn namespace expr))))
+
+(defun js2-parse-primary-expr ()
+  "Parses a literal (leaf) expression of some sort.
+Includes complex literals such as functions, object-literals,
+array-literals, array comprehensions and regular expressions."
+  (let ((tt-flagged (js2-next-flagged-token))
+        pn      ; parent node  (usually return value)
+        tt
+        px-pos  ; paren-expr pos
+        len
+        flags   ; regexp flags
+        expr)
+    (setq tt js2-current-token)
+    (cond
+     ((= tt js2-FUNCTION)
+      (js2-parse-function 'FUNCTION_EXPRESSION))
+     ((= tt js2-LB)
+      (js2-parse-array-literal))
+     ((= tt js2-LC)
+      (js2-parse-object-literal))
+     ((= tt js2-LET)
+      (js2-parse-let js2-token-beg))
+     ((= tt js2-LP)
+      (setq px-pos js2-token-beg
+            expr (js2-parse-expr))
+      (js2-must-match js2-RP "msg.no.paren")
+      (setq pn (make-js2-paren-node :pos px-pos
+                                    :expr expr
+                                    :len (- js2-token-end px-pos)))
+      (js2-node-add-children pn (js2-paren-node-expr pn))
+      pn)
+     ((= tt js2-XMLATTR)
+      (js2-must-have-xml)
+      (js2-parse-attribute-access))
+     ((= tt js2-NAME)
+      (js2-parse-name tt-flagged tt))
+     ((= tt js2-NUMBER)
+      (make-js2-number-node))
+     ((= tt js2-STRING)
+      (prog1
+          (make-js2-string-node)
+        (js2-record-face 'font-lock-string-face)))
+     ((or (= tt js2-DIV) (= tt js2-ASSIGN_DIV))
+      ;; Got / or /= which in this context means a regexp literal
+      (setq px-pos js2-token-beg)
+      (js2-read-regexp tt)
+      (setq flags js2-ts-regexp-flags
+            js2-ts-regexp-flags nil)
+      (prog1
+          (make-js2-regexp-node :pos px-pos
+                                :len (- js2-ts-cursor px-pos)
+                                :value js2-ts-string
+                                :flags flags)
+        (js2-set-face px-pos js2-ts-cursor 'font-lock-string-face 'record)
+        (put-text-property px-pos js2-ts-cursor 'syntax-table '(2))))
+     ((or (= tt js2-NULL)
+          (= tt js2-THIS)
+          (= tt js2-FALSE)
+          (= tt js2-TRUE))
+      (make-js2-keyword-node :type tt))
+     ((= tt js2-RESERVED)
+      (js2-report-error "msg.reserved.id")
+      (make-js2-name-node))
+     ((= tt js2-ERROR)
+      ;; the scanner or one of its subroutines reported the error.
+      (make-js2-error-node))
+     ((= tt js2-EOF)
+      (setq px-pos (point-at-bol)
+            len (- js2-ts-cursor px-pos))
+      (js2-report-error "msg.unexpected.eof" nil px-pos len)
+      (make-js2-error-node :pos px-pos :len len))
+     (t
+      (js2-report-error "msg.syntax")
+      (make-js2-error-node)))))
+
+(defun js2-parse-name (tt-flagged tt)
+  (let ((name js2-ts-string)
+        (name-pos js2-token-beg))
+      (if (and (js2-flag-set-p tt-flagged js2-ti-check-label)
+               (= (js2-peek-token) js2-COLON))
+          (prog1
+            ;; Do not consume colon, it is used as unwind indicator
+            ;; to return to statementHelper.
+            (make-js2-label-node :pos name-pos
+                                 :len (- js2-token-end name-pos)
+                                 :name name)
+            (js2-set-face name-pos
+                          js2-token-end
+                          'font-lock-variable-name-face 'record))
+        ;; Otherwise not a label, just a name.  Unfortunately peeking
+        ;; the next token to check for a colon has biffed js2-token-beg
+        ;; and js2-token-end.  We store the name's bounds in buffer vars
+        ;; and `js2-create-name-node' uses them.
+        (js2-save-name-token-data name-pos name)
+        (if js2-compiler-xml-available
+            (js2-parse-property-name nil name 0)
+          (js2-create-name-node 'check-activation)))))
+
+(defsubst js2-parse-warn-trailing-comma (msg pos elems comma-pos)
+  (js2-add-strict-warning
+   msg nil
+   ;; back up from comma to beginning of line or array/objlit
+   (max (if elems
+            (js2-node-pos (car elems))
+          pos)
+        (save-excursion
+          (goto-char comma-pos)
+          (back-to-indentation)
+          (point)))
+   comma-pos))
+
+(defun js2-parse-array-literal ()
+  (let ((pos js2-token-beg)
+        (end js2-token-end)
+        (after-lb-or-comma t)
+        after-comma
+        tt
+        elems
+        pn
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (cond
+       ;; comma
+       ((= tt js2-COMMA)
+        (js2-consume-token)
+        (setq after-comma js2-token-end)
+        (if (not after-lb-or-comma)
+            (setq after-lb-or-comma t)
+          (push nil elems)))
+       ;; end of array
+       ((or (= tt js2-RB)
+            (= tt js2-EOF))  ; prevent infinite loop
+        (if (= tt js2-EOF)
+            (js2-report-error "msg.no.bracket.arg" nil pos)
+          (js2-consume-token))
+        (setq continue nil
+              end js2-token-end
+              pn (make-js2-array-node :pos pos
+                                      :len (- js2-ts-cursor pos)
+                                      :elems (nreverse elems)))
+        (apply #'js2-node-add-children pn (js2-array-node-elems pn))
+        (when after-comma
+          (js2-parse-warn-trailing-comma "msg.array.trailing.comma"
+                                         pos elems after-comma)))
+       ;; array comp
+       ((and (>= js2-language-version 170)
+             (= tt js2-FOR)          ; check for array comprehension
+             (not after-lb-or-comma) ; "for" can't follow a comma
+             elems                   ; must have at least 1 element
+             (not (cdr elems)))      ; but no 2nd element
+        (setf continue nil
+              pn (js2-parse-array-comprehension (car elems) pos)))
+       ;; another element
+       (t
+        (unless after-lb-or-comma
+          (js2-report-error "msg.no.bracket.arg"))
+        (push (js2-parse-assign-expr) elems)
+        (setq after-lb-or-comma nil
+              after-comma nil))))
+    pn))
+
+(defun js2-parse-array-comprehension (expr pos)
+  "Parse a JavaScript 1.7 Array Comprehension.
+EXPR is the first expression after the opening left-bracket.
+POS is the beginning of the LB token preceding EXPR.
+We should have just parsed the 'for' keyword before calling this function."
+  (let (loops
+        filter
+        if-pos
+        result)
+    (while (= (js2-peek-token) js2-FOR)
+      (push (js2-parse-array-comp-loop) loops))
+    (when (= (js2-peek-token) js2-IF)
+      (js2-consume-token)
+      (setq if-pos (- js2-token-beg pos)  ; relative
+            filter (js2-parse-condition)))
+    (js2-must-match js2-RB "msg.no.bracket.arg" pos)
+    (setq result (make-js2-array-comp-node :pos pos
+                                           :len (- js2-ts-cursor pos)
+                                           :result expr
+                                           :loops (nreverse loops)
+                                           :filter (car filter)
+                                           :lp (js2-relpos (second filter) pos)
+                                           :rp (js2-relpos (third filter) pos)
+                                           :if-pos if-pos))
+    (apply #'js2-node-add-children result expr (car filter)
+           (js2-array-comp-node-loops result))
+    result))
+
+(defun js2-parse-array-comp-loop ()
+  "Parse a 'for [each] (foo in bar)' expression in an Array comprehension.
+Last token peeked should be the initial FOR."
+  (let ((pos js2-token-beg)
+        (pn (make-js2-array-comp-loop-node))
+        tt
+        iter
+        obj
+        foreach-p
+        in-pos
+        each-pos
+        lp
+        rp)
+    (assert (= (js2-next-token) js2-FOR))  ; consumes token
+    (js2-push-scope pn)
+    (unwind-protect
+        (progn
+          (when (js2-match-token js2-NAME)
+            (if (string= js2-ts-string "each")
+                (progn
+                  (setq foreach-p t
+                        each-pos (- js2-token-beg pos)) ; relative
+                  (js2-record-face 'font-lock-keyword-face))
+              (js2-report-error "msg.no.paren.for")))
+          (if (js2-must-match js2-LP "msg.no.paren.for")
+              (setq lp (- js2-token-beg pos)))
+          (setq tt (js2-peek-token))
+          (cond
+           ((or (= tt js2-LB)
+                (= tt js2-LC))
+            ;; handle destructuring assignment
+            (setq iter (js2-parse-primary-expr)))
+           ((js2-valid-prop-name-token tt)
+            (js2-consume-token)
+            (setq iter (js2-create-name-node)))
+           (t
+            (js2-report-error "msg.bad.var")))
+          ;; Define as a let since we want the scope of the variable to
+          ;; be restricted to the array comprehension
+          (if (js2-name-node-p iter)
+              (js2-define-symbol js2-LET (js2-name-node-name iter) pn t))
+          (if (js2-must-match js2-IN "msg.in.after.for.name")
+              (setq in-pos (- js2-token-beg pos)))
+          (setq obj (js2-parse-expr))
+          (if (js2-must-match js2-RP "msg.no.paren.for.ctrl")
+              (setq rp (- js2-token-beg pos)))
+          (setf (js2-node-pos pn) pos
+                (js2-node-len pn) (- js2-ts-cursor pos)
+                (js2-array-comp-loop-node-iterator pn) iter
+                (js2-array-comp-loop-node-object pn) obj
+                (js2-array-comp-loop-node-in-pos pn) in-pos
+                (js2-array-comp-loop-node-each-pos pn) each-pos
+                (js2-array-comp-loop-node-foreach-p pn) foreach-p
+                (js2-array-comp-loop-node-lp pn) lp
+                (js2-array-comp-loop-node-rp pn) rp)
+          (js2-node-add-children pn iter obj))
+      (js2-pop-scope))
+    pn))
+
+(defun js2-parse-object-literal ()
+  (let ((pos js2-token-beg)
+        tt
+        elems
+        result
+        after-comma
+        (continue t))
+    (while continue
+      (setq tt (js2-peek-token))
+      (cond
+       ;; {foo: ...}, {'foo': ...}, {get foo() {...}}, or {set foo(x) {...}}
+       ((or (js2-valid-prop-name-token tt)
+            (= tt js2-STRING))
+        (setq after-comma nil
+              result (js2-parse-named-prop tt))
+        (if (and (null result)
+                 (not js2-recover-from-parse-errors))
+            (setq continue nil)
+          (push result elems)))
+       ;; {12: x} or {10.7: x}
+       ((= tt js2-NUMBER)
+        (js2-consume-token)
+        (setq after-comma nil)
+        (push (js2-parse-plain-property (make-js2-number-node)) elems))
+       ;; trailing comma
+       ((= tt js2-RC)
+        (setq continue nil)
+        (if after-comma
+            (js2-parse-warn-trailing-comma "msg.extra.trailing.comma"
+                                           pos elems after-comma)))
+       (t
+        (js2-report-error "msg.bad.prop")
+        (unless js2-recover-from-parse-errors
+          (setq continue nil))))         ; end switch
+      (if (js2-match-token js2-COMMA)
+          (setq after-comma js2-token-end)
+        (setq continue nil)))           ; end loop
+    (js2-must-match js2-RC "msg.no.brace.prop")
+    (setq result (make-js2-object-node :pos pos
+                                       :len (- js2-ts-cursor pos)
+                                       :elems (nreverse elems)))
+    (apply #'js2-node-add-children result (js2-object-node-elems result))
+    result))
+
+(defun js2-parse-named-prop (tt)
+  "Parse a name, string, or getter/setter object property."
+  (js2-consume-token)
+  (let ((string-prop (and (= tt js2-STRING)
+                          (make-js2-string-node)))
+        expr
+        (ppos js2-token-beg)
+        (pend js2-token-end)
+        (name (js2-create-name-node))
+        (prop js2-ts-string))
+    (if (and (= tt js2-NAME)
+             (= (js2-peek-token) js2-NAME)
+             (or (string= prop "get")
+                 (string= prop "set")))
+        (progn
+          ;; getter/setter prop
+          (js2-consume-token)
+          (js2-set-face ppos pend 'font-lock-keyword-face 'record)  ; get/set
+          (js2-record-face 'font-lock-function-name-face)      ; for peeked 
name
+          (setq name (js2-create-name-node)) ; discard get/set & use peeked 
name
+          (js2-parse-getter-setter-prop ppos name (string= prop "get")))
+      ;; regular prop
+      (prog1
+          (setq expr (js2-parse-plain-property (or string-prop name)))
+        (js2-set-face ppos pend
+                      (if (js2-function-node-p
+                           (js2-object-prop-node-right expr))
+                          'font-lock-function-name-face
+                        'font-lock-variable-name-face)
+                      'record)))))
+
+(defun js2-parse-plain-property (prop)
+  "Parse a non-getter/setter property in an object literal.
+PROP is the node representing the property:  a number, name or string."
+  (js2-must-match js2-COLON "msg.no.colon.prop")
+  (let* ((pos (js2-node-pos prop))
+        (colon (- js2-token-beg pos))
+        (expr (js2-parse-assign-expr))
+        (result (make-js2-object-prop-node
+                 :pos pos
+                 ;; don't include last consumed token in length
+                 :len (- (+ (js2-node-pos expr)
+                            (js2-node-len expr))
+                         pos)
+                 :left prop
+                 :right expr
+                 :op-pos colon)))
+    (js2-node-add-children result prop expr)
+    result))
+
+(defun js2-parse-getter-setter-prop (pos prop get-p)
+  "Parse getter or setter property in an object literal.
+JavaScript syntax is:
+
+  { get foo() {...}, set foo(x) {...} }
+
+POS is the start position of the `get' or `set' keyword.
+PROP is the `js2-name-node' representing the property name.
+GET-P is non-nil if the keyword was `get'."
+  (let ((type (if get-p js2-GET js2-SET))
+        result
+        end
+        (fn (js2-parse-function 'FUNCTION_EXPRESSION)))
+    ;; it has to be an anonymous function, as we already parsed the name
+    (if (/= (js2-node-type fn) js2-FUNCTION)
+        (js2-report-error "msg.bad.prop")
+      (if (plusp (length (js2-function-name fn)))
+          (js2-report-error "msg.bad.prop")))
+    (js2-node-set-prop fn 'GETTER_SETTER type)  ; for codegen
+    (setq end (js2-node-end fn)
+          result (make-js2-getter-setter-node :type type
+                                              :pos pos
+                                              :len (- end pos)
+                                              :left prop
+                                              :right fn))
+    (js2-node-add-children result prop fn)
+    result))
+
+(defun js2-create-name-node (&optional check-activation-p token)
+  "Create a name node using the token info from last scanned name.
+In some cases we need to either synthesize a name node, or we lost
+the name token information by peeking.  If the TOKEN parameter is
+not `js2-NAME', then we use the token info saved in instance vars."
+  (let ((beg js2-token-beg)
+        (s js2-ts-string)
+        name)
+    (when (/= js2-current-token js2-NAME)
+      (setq beg (or js2-prev-name-token-start js2-ts-cursor)
+            s js2-prev-name-token-string
+            js2-prev-name-token-start nil
+            js2-prev-name-token-string nil))
+    (setq name (make-js2-name-node :pos beg
+                                   :name s
+                                   :len (length s)))
+    (if check-activation-p
+        (js2-check-activation-name s (or token js2-NAME)))
+    name))
+
+;;; Indentation support
+
+;; This indenter is based on Karl Landström's "javascript.el" indenter.
+;; Karl cleverly deduces that the desired indentation level is often a
+;; function of paren/bracket/brace nesting depth, which can be determined
+;; quickly via the built-in `parse-partial-sexp' function.  His indenter
+;; then does some equally clever checks to see if we're in the context of a
+;; substatement of a possibly braceless statement keyword such as if, while,
+;; or finally.  This approach yields pretty good results.
+
+;; The indenter is often "wrong", however, and needs to be overridden.
+;; The right long-term solution is probably to emulate (or integrate
+;; with) cc-engine, but it's a nontrivial amount of coding.  Even when a
+;; parse tree from `js2-parse' is present, which is not true at the
+;; moment the user is typing, computing indentation is still thousands
+;; of lines of code to handle every possible syntactic edge case.
+
+;; In the meantime, the compromise solution is that we offer a "bounce
+;; indenter", configured with `js2-bounce-indent-p', which cycles the
+;; current line indent among various likely guess points.  This approach
+;; is far from perfect, but should at least make it slightly easier to
+;; move the line towards its desired indentation when manually
+;; overriding Karl's heuristic nesting guesser.
+
+;; I've made miscellaneous tweaks to Karl's code to handle some Ecma
+;; extensions such as `let' and Array comprehensions.  Major kudos to
+;; Karl for coming up with the initial approach, which packs a lot of
+;; punch for so little code.
+
+(defconst js-possibly-braceless-keyword-re
+  (regexp-opt
+   '("catch" "do" "else" "finally" "for" "if" "try" "while" "with" "let")
+   'words)
+  "Regular expression matching keywords that are optionally
+followed by an opening brace.")
+
+(defconst js-indent-operator-re
+  (concat "[-+*/%<>=&^|?:.]\\([^-+*/]\\|$\\)\\|"
+          (regexp-opt '("in" "instanceof") 'words))
+  "Regular expression matching operators that affect indentation
+of continued expressions.")
+
+;; This function has horrible results if you're typing an array
+;; such as [[1, 2], [3, 4], [5, 6]].  Bounce indenting -really- sucks
+;; in conjunction with electric-indent, so just disabling it.
+(defsubst js2-code-at-bol-p ()
+  "Return t if the first character on line is non-whitespace."
+  nil)
+
+(defun js2-insert-and-indent (key)
+  "Run command bound to key and indent current line. Runs the command
+bound to KEY in the global keymap and indents the current line."
+  (interactive (list (this-command-keys)))
+  (let ((cmd (lookup-key (current-global-map) key)))
+    (if (commandp cmd)
+        (call-interactively cmd)))
+  ;; don't do the electric keys inside comments or strings,
+  ;; and don't do bounce-indent with them.
+  (let ((parse-state (parse-partial-sexp (point-min) (point)))
+        (js2-bounce-indent-p (js2-code-at-bol-p)))
+    (unless (or (nth 3 parse-state)
+                (nth 4 parse-state))
+      (indent-according-to-mode))))
+
+(defun js-re-search-forward-inner (regexp &optional bound count)
+  "Auxiliary function for `js-re-search-forward'."
+  (let ((parse)
+        (saved-point (point-min)))
+    (while (> count 0)
+      (re-search-forward regexp bound)
+      (setq parse (parse-partial-sexp saved-point (point)))
+      (cond ((nth 3 parse)
+             (re-search-forward
+              (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
+              (save-excursion (end-of-line) (point)) t))
+            ((nth 7 parse)
+             (forward-line))
+            ((or (nth 4 parse)
+                 (and (eq (char-before) ?\/) (eq (char-after) ?\*)))
+             (re-search-forward "\\*/"))
+            (t
+             (setq count (1- count))))
+      (setq saved-point (point))))
+  (point))
+
+(defun js-re-search-forward (regexp &optional bound noerror count)
+  "Search forward but ignore strings and comments. Invokes
+`re-search-forward' but treats the buffer as if strings and
+comments have been removed."
+  (let ((saved-point (point))
+        (search-expr
+         (cond ((null count)
+                '(js-re-search-forward-inner regexp bound 1))
+               ((< count 0)
+                '(js-re-search-backward-inner regexp bound (- count)))
+               ((> count 0)
+                '(js-re-search-forward-inner regexp bound count)))))
+    (condition-case err
+        (eval search-expr)
+      (search-failed
+       (goto-char saved-point)
+       (unless noerror
+         (error (error-message-string err)))))))
+
+(defun js-re-search-backward-inner (regexp &optional bound count)
+  "Auxiliary function for `js-re-search-backward'."
+  (let ((parse)
+        (saved-point (point-min)))
+    (while (> count 0)
+      (re-search-backward regexp bound)
+      (setq parse (parse-partial-sexp saved-point (point)))
+      (cond ((nth 3 parse)
+             (re-search-backward
+              (concat "\\([^\\]\\|^\\)" (string (nth 3 parse)))
+              (save-excursion (beginning-of-line) (point)) t))
+            ((nth 7 parse)
+             (goto-char (nth 8 parse)))
+            ((or (nth 4 parse)
+                 (and (eq (char-before) ?/) (eq (char-after) ?*)))
+             (re-search-backward "/\\*"))
+            (t
+             (setq count (1- count))))))
+  (point))
+
+(defun js-re-search-backward (regexp &optional bound noerror count)
+  "Search backward but ignore strings and comments. Invokes
+`re-search-backward' but treats the buffer as if strings and
+comments have been removed."
+  (let ((saved-point (point))
+        (search-expr
+         (cond ((null count)
+                '(js-re-search-backward-inner regexp bound 1))
+               ((< count 0)
+                '(js-re-search-forward-inner regexp bound (- count)))
+               ((> count 0)
+                '(js-re-search-backward-inner regexp bound count)))))
+    (condition-case err
+        (eval search-expr)
+      (search-failed
+       (goto-char saved-point)
+       (unless noerror
+         (error (error-message-string err)))))))
+
+(defun js-looking-at-operator-p ()
+  "Return non-nil if text after point is an operator (that is not
+a comma)."
+  (save-match-data
+    (and (looking-at js-indent-operator-re)
+         (or (not (looking-at ":"))
+             (save-excursion
+               (and (js-re-search-backward "[?:{]\\|\\<case\\>" nil t)
+                    (looking-at "?")))))))
+
+(defun js-continued-expression-p ()
+  "Returns non-nil if the current line continues an expression."
+  (save-excursion
+    (back-to-indentation)
+    (or (js-looking-at-operator-p)
+        (and (js-re-search-backward "\n" nil t)
+            (progn
+              (skip-chars-backward " \t")
+              (backward-char)
+              (and (js-looking-at-operator-p)
+                   (and (progn (backward-char)
+                               (not (looking-at 
"\\*\\|++\\|--\\|/[/*]"))))))))))
+
+(defun js-end-of-do-while-loop-p ()
+  "Returns non-nil if word after point is `while' of a do-while
+statement, else returns nil. A braceless do-while statement
+spanning several lines requires that the start of the loop is
+indented to the same column as the current line."
+  (interactive)
+  (save-excursion
+    (save-match-data
+      (when (looking-at "\\s-*\\<while\\>")
+       (if (save-excursion
+             (skip-chars-backward "[ \t\n]*}")
+             (looking-at "[ \t\n]*}"))
+           (save-excursion
+             (backward-list) (backward-word 1) (looking-at "\\<do\\>"))
+         (js-re-search-backward "\\<do\\>" (point-at-bol) t)
+         (or (looking-at "\\<do\\>")
+             (let ((saved-indent (current-indentation)))
+               (while (and (js-re-search-backward "^[ \t]*\\<" nil t)
+                           (/= (current-indentation) saved-indent)))
+               (and (looking-at "[ \t]*\\<do\\>")
+                    (not (js-re-search-forward
+                          "\\<while\\>" (point-at-eol) t))
+                    (= (current-indentation) saved-indent)))))))))
+
+(defun js-ctrl-statement-indentation ()
+  "Returns the proper indentation of the current line if it
+starts the body of a control statement without braces, else
+returns nil."
+  (let (forward-sexp-function)  ; temporarily unbind it
+    (save-excursion
+      (back-to-indentation)
+      (when (save-excursion
+              (and (not (js2-same-line (point-min)))
+                   (not (looking-at "{"))
+                   (js-re-search-backward "[[:graph:]]" nil t)
+                   (not (looking-at "[{([]"))
+                   (progn
+                     (forward-char)
+                     ;; scan-sexps sometimes throws an error
+                     (ignore-errors (backward-sexp))
+                     (when (looking-at "(") (backward-word 1))
+                     (and (save-excursion
+                            (skip-chars-backward " \t}" (point-at-bol))
+                            (bolp))
+                          (looking-at js-possibly-braceless-keyword-re)
+                          (not (js-end-of-do-while-loop-p))))))
+        (save-excursion
+          (goto-char (match-beginning 0))
+          (+ (current-indentation) js2-basic-offset))))))
+
+(defun js2-indent-in-array-comp (parse-status)
+  "Return non-nil if we think we're in an array comprehension.
+In particular, return the buffer position of the first `for' kwd."
+  (let ((end (point)))
+    (when (nth 1 parse-status)
+      (save-excursion
+        (goto-char (nth 1 parse-status))
+        (when (looking-at "\\[")
+          (forward-char 1)
+          (js2-forward-sws)
+          (if (looking-at "[[{]")
+              (let (forward-sexp-function) ; use lisp version
+                (forward-sexp)             ; skip destructuring form
+                (js2-forward-sws)
+                (if (and (/= (char-after) ?,) ; regular array
+                         (looking-at "for"))
+                    (match-beginning 0)))
+            ;; to skip arbitrary expressions we need the parser,
+            ;; so we'll just guess at it.
+            (if (re-search-forward "[^,]* \\(for\\) " end t)
+                (match-beginning 1))))))))
+
+(defun js2-array-comp-indentation (parse-status for-kwd)
+  (if (js2-same-line for-kwd)
+      ;; first continuation line
+      (save-excursion
+        (goto-char (nth 1 parse-status))
+        (forward-char 1)
+        (skip-chars-forward " \t")
+        (current-column))
+    (save-excursion
+      (goto-char for-kwd)
+      (current-column))))
+
+(defun js-proper-indentation (parse-status)
+  "Return the proper indentation for the current line."
+  (save-excursion
+    (back-to-indentation)
+    (let ((ctrl-stmt-indent (js-ctrl-statement-indentation))
+          (same-indent-p (looking-at "[]})]\\|\\<case\\>\\|\\<default\\>"))
+          (continued-expr-p (js-continued-expression-p))
+          (bracket (nth 1 parse-status))
+          beg)
+      (cond
+       ;; indent array comprehension continuation lines specially
+       ((and bracket
+             (not (js2-same-line bracket))
+             (setq beg (js2-indent-in-array-comp parse-status))
+             (>= (point) (save-excursion
+                           (goto-char beg)
+                           (point-at-bol)))) ; at or after first loop?
+        (js2-array-comp-indentation parse-status beg))
+
+       (ctrl-stmt-indent)
+
+       (bracket
+        (goto-char bracket)
+        (cond
+         ((looking-at "[({[][ \t]*\\(/[/*]\\|$\\)")
+          (let ((p (parse-partial-sexp (point-at-bol) (point))))
+            (when (save-excursion (skip-chars-backward " \t)")
+                                  (looking-at ")"))
+              (backward-list))
+            (if (nth 1 p)
+                (progn (goto-char (1+ (nth 1 p)))
+                       (skip-chars-forward " \t"))
+              (back-to-indentation))
+            (cond (same-indent-p
+                   (current-column))
+                  (continued-expr-p
+                   (+ (current-column) (* 2 js2-basic-offset)))
+                  (t
+                   (+ (current-column) js2-basic-offset)))))
+         (t
+          (unless same-indent-p
+            (forward-char)
+            (skip-chars-forward " \t"))
+          (current-column))))
+
+       (continued-expr-p js2-basic-offset)
+       (t 0)))))
+
+(defun js2-lineup-comment (parse-status)
+  "Indent a multi-line block comment continuation line."
+  (let* ((beg (nth 8 parse-status))
+         (first-line (js2-same-line beg))
+         (offset (save-excursion
+                   (goto-char beg)
+                   (if (looking-at "/\\*")
+                       (+ 1 (current-column))
+                     0))))
+    (unless first-line
+      (indent-line-to offset))))
+
+(defun js2-backward-sws ()
+  "Move backward through whitespace and comments."
+  (interactive)
+  (while (forward-comment -1)))
+
+(defun js2-forward-sws ()
+  "Move forward through whitespace and comments."
+  (interactive)
+  (while (forward-comment 1)))
+
+(defsubst js2-current-indent (&optional pos)
+  "Return column of indentation on current line.
+If POS is non-nil, go to that point and return indentation for that line."
+  (save-excursion
+    (if pos
+        (goto-char pos))
+    (back-to-indentation)
+    (current-column)))
+
+(defsubst js2-arglist-close ()
+  "Return non-nil if we're on a line beginning with a close-paren/brace."
+  (save-match-data
+    (save-excursion
+      (goto-char (point-at-bol))
+      (js2-forward-sws)
+      (looking-at "[])}]"))))
+
+(defsubst js2-indent-looks-like-label-p ()
+  (goto-char (point-at-bol))
+  (js2-forward-sws)
+  (looking-at (concat js2-mode-identifier-re ":")))
+
+(defun js2-indent-in-objlit-p (parse-status)
+  "Return non-nil if this looks like an object-literal entry."
+  (let ((start (nth 1 parse-status)))
+    (and
+     start
+     (save-excursion
+       (and (zerop (forward-line -1))
+            (not (< (point) start))     ; crossed a {} boundary
+            (js2-indent-looks-like-label-p)))
+     (save-excursion
+       (js2-indent-looks-like-label-p)))))
+
+;; if prev line looks like foobar({ then we're passing an object
+;; literal to a function call, and people pretty much always want to
+;; de-dent back to the previous line, so move the 'basic-offset'
+;; position to the front.
+(defsubst js2-indent-objlit-arg-p (parse-status)
+  (save-excursion
+    (back-to-indentation)
+    (js2-backward-sws)
+    (and (eq (1- (point)) (nth 1 parse-status))
+         (eq (char-before) ?{)
+         (progn
+           (forward-char -1)
+           (skip-chars-backward " \t")
+           (eq (char-before) ?\()))))
+
+(defsubst js2-indent-case-block-p ()
+  (save-excursion
+    (back-to-indentation)
+    (js2-backward-sws)
+    (goto-char (point-at-bol))
+    (skip-chars-forward " \t")
+    (save-match-data
+      (looking-at "case\\s-.+:"))))
+
+(defsubst js2-syntax-bol ()
+  "Return the point at the first non-whitespace char on the line.
+Returns `point-at-bol' if the line is empty."
+  (save-excursion
+    (beginning-of-line)
+    (skip-chars-forward " \t")
+    (point)))
+
+(defun js2-bounce-indent (normal-col parse-status)
+  "Cycle among alternate computed indentation positions.
+PARSE-STATUS is the result of `parse-partial-sexp' from the beginning
+of the buffer to the current point.  NORMAL-COL is the indentation
+column computed by the heuristic guesser based on current paren,
+bracket, brace and statement nesting."
+  (let ((cur-indent (js2-current-indent))
+        (old-buffer-undo-list buffer-undo-list)
+        ;; Emacs 21 only has `count-lines', not `line-number-at-pos'
+        (current-line (save-excursion
+                        (forward-line 0)  ; move to bol
+                        (1+ (count-lines (point-min) (point)))))
+        positions
+        pos
+        anchor
+        arglist-cont
+        same-indent
+        prev-line-col
+        basic-offset
+        computed-pos)
+    ;; temporarily don't record undo info, if user requested this
+    (if js2-mode-indent-inhibit-undo
+        (setq buffer-undo-list t))
+    (unwind-protect
+        (progn
+          ;; first likely point:  indent from beginning of previous code line
+          (push (setq basic-offset
+                      (+ (save-excursion
+                           (back-to-indentation)
+                           (js2-backward-sws)
+                           (back-to-indentation)
+                           (setq prev-line-col (current-column)))
+                         js2-basic-offset))
+                positions)
+
+          ;; (first + epsilon) likely point:  indent 2x from beginning of
+          ;; previous code line.  Some companies like this approach.  Ahem.
+          ;; Seriously, though -- 4-space indent for expression continuation
+          ;; lines isn't a bad idea.  We should eventually implement it
+          ;; that way.
+          (push (setq basic-offset
+                      (+ (save-excursion
+                           (back-to-indentation)
+                           (js2-backward-sws)
+                           (back-to-indentation)
+                           (setq prev-line-col (current-column)))
+                         (* 2 js2-basic-offset)))
+                positions)
+
+          ;; second likely point:  indent from assign-expr RHS.  This
+          ;; is just a crude guess based on finding " = " on the previous
+          ;; line containing actual code.
+          (setq pos (save-excursion
+                      (save-match-data
+                        (forward-line -1)
+                        (goto-char (point-at-bol))
+                        (when (re-search-forward "\\s-+\\(=\\)\\s-+"
+                                                 (point-at-eol) t)
+                          (goto-char (match-end 1))
+                          (skip-chars-forward " \t\r\n")
+                          (current-column)))))
+          (when pos
+            (incf pos js2-basic-offset)
+            (unless (member pos positions)
+              (push pos positions)))
+
+          ;; third likely point:  same indent as previous line of code.
+          ;; Make it the first likely point if we're not on an
+          ;; arglist-close line and previous line ends in a comma, or
+          ;; both this line and prev line look like object-literal
+          ;; elements.
+          (setq pos (save-excursion
+                      (goto-char (point-at-bol))
+                      (js2-backward-sws)
+                      (back-to-indentation)
+                      (prog1
+                          (current-column)
+                        ;; while we're here, look for trailing comma
+                        (if (save-excursion
+                              (goto-char (point-at-eol))
+                              (js2-backward-sws)
+                              (eq (char-before) ?,))
+                            (setq arglist-cont (1- (point)))))))
+          (when pos
+            (if (and (or arglist-cont
+                         (js2-indent-in-objlit-p parse-status))
+                     (not (js2-arglist-close)))
+                (setq same-indent pos))
+            (unless (member pos positions)
+              (push pos positions)))
+
+          ;; fourth likely point:  first preceding code with less indentation
+          ;; than the immediately preceding code line.
+          (setq pos (save-excursion
+                      (js2-backward-sws)
+                      (back-to-indentation)
+                      (setq anchor (current-column))
+                      (while (and (zerop (forward-line -1))
+                                  (>= (progn
+                                        (back-to-indentation)
+                                        (current-column))
+                                      anchor)))
+                      (setq pos (current-column))))
+          (unless (member pos positions)
+            (push pos positions))
+
+          ;; put nesting-heuristic position first in list, sort rest
+          (setq positions (nreverse (sort positions '<)))
+          (setq positions (cons normal-col (delete normal-col positions)))
+
+          ;; comma-list continuation lines:  prev line indent takes precedence
+          (if same-indent
+              (setq positions
+                    (cons same-indent
+                          (sort (delete same-indent positions) '<))))
+
+          ;; common special cases where we want to indent in from previous line
+          (if (or (js2-indent-case-block-p)
+                  (js2-indent-objlit-arg-p parse-status))
+              (setq positions
+                    (cons basic-offset
+                          (delete basic-offset positions))))
+
+          ;; record whether we're already sitting on one of the alternatives
+          (setq pos (member cur-indent positions))
+          (cond
+           ;; case 0:  we're one one of the alternatives and this is the
+           ;; first time they've pressed TAB on this line (best-guess).
+           ((and js2-mode-indent-ignore-first-tab
+                 pos
+                 ;; first time pressing TAB on this line?
+                 (not (eq js2-mode-last-indented-line current-line)))
+            ;; do nothing
+            (setq computed-pos nil))
+           ;; case 1:  only one computed position => use it
+           ((null (cdr positions))
+            (setq computed-pos 0))
+           ;; case 2:  not on any of the computed spots => use main spot
+           ((not pos)
+            (setq computed-pos 0))
+           ;; case 3:  on last position:  cycle to first position
+           ((null (cdr pos))
+            (setq computed-pos 0))
+           ;; case 4:  on intermediate position:  cycle to next position
+           (t
+            (setq computed-pos (js2-position (second pos) positions))))
+
+          ;; see if any hooks want to indent; otherwise we do it
+          (loop with result = nil
+                for hook in js2-indent-hook
+                while (null result)
+                do
+                (setq result (funcall hook positions computed-pos))
+                finally do
+                (unless (or result (null computed-pos))
+                  (indent-line-to (nth computed-pos positions)))))
+
+      ;; finally
+      (if js2-mode-indent-inhibit-undo
+          (setq buffer-undo-list old-buffer-undo-list))
+      ;; see commentary for `js2-mode-last-indented-line'
+      (setq js2-mode-last-indented-line current-line))))
+
+(defsubst js2-1-line-comment-continuation-p ()
+  "Return t if we're in a 1-line comment continuation.
+If so, we don't ever want to use bounce-indent."
+  (save-excursion
+    (save-match-data
+      (and (progn
+             (forward-line 0)
+             (looking-at "\\s-*//"))
+           (progn
+             (forward-line -1)
+             (forward-line 0)
+             (when (looking-at "\\s-*$")
+               (js2-backward-sws)
+               (forward-line 0))
+             (looking-at "\\s-*//"))))))
+
+(defun js2-indent-line ()
+  "Indent the current line as JavaScript source text."
+  (interactive)
+  (let (parse-status
+        current-indent
+        offset
+        indent-col
+        moved
+        ;; don't whine about errors/warnings when we're indenting.
+        ;; This has to be set before calling parse-partial-sexp below.
+        (inhibit-point-motion-hooks t))
+    (setq parse-status (save-excursion
+                          (parse-partial-sexp (point-min)
+                                              (point-at-bol)))
+          offset (- (point) (save-excursion
+                               (back-to-indentation)
+                               (setq current-indent (current-column))
+                               (point))))
+    (js2-with-underscore-as-word-syntax
+     (if (nth 4 parse-status)
+         (js2-lineup-comment parse-status)
+       (setq indent-col (js-proper-indentation parse-status))
+       ;; see comments below about js2-mode-last-indented-line
+       (when
+           (cond
+            ;; bounce-indenting is disabled during electric-key indent.
+            ;; It doesn't work well on first line of buffer.
+            ((and js2-bounce-indent-p
+                  (not (js2-same-line (point-min)))
+                  (not (js2-1-line-comment-continuation-p)))
+             (js2-bounce-indent indent-col parse-status)
+             (setq moved t))
+            ;; just indent to the guesser's likely spot
+            ((/= current-indent indent-col)
+             (indent-line-to indent-col)
+             (setq moved t)))
+         (when (and moved (plusp offset))
+           (forward-char offset)))))))
+
+(defun js2-indent-region (start end)
+  "Indent the region, but don't use bounce indenting."
+  (let ((js2-bounce-indent-p nil)
+        (indent-region-function nil))
+    (indent-region start end nil)))  ; nil for byte-compiler
+
+;;;###autoload (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
+
+;;;###autoload
+(defun js2-mode ()
+  "Major mode for editing JavaScript code."
+  (interactive)
+  (kill-all-local-variables)
+  (set-syntax-table js2-mode-syntax-table)
+  (use-local-map js2-mode-map)
+  (setq major-mode 'js2-mode
+        mode-name "JavaScript-IDE"
+        comment-start "//"  ; used by comment-region; don't change it
+        comment-end "")
+  (setq local-abbrev-table js2-mode-abbrev-table)
+  (set (make-local-variable 'max-lisp-eval-depth)
+       (max max-lisp-eval-depth 3000))
+  (set (make-local-variable 'indent-line-function) #'js2-indent-line)
+  (set (make-local-variable 'indent-region-function) #'js2-indent-region)
+
+  ;; I tried an "improvement" to `c-fill-paragraph' that worked out badly
+  ;; on most platforms other than the one I originally wrote it on.  So it's
+  ;; back to `c-fill-paragraph'.  Still not perfect, though -- something to do
+  ;; with our binding of the RET key inside comments:  short lines stay short.
+  (set (make-local-variable 'fill-paragraph-function) #'c-fill-paragraph)
+
+  (set (make-local-variable 'before-save-hook) #'js2-before-save)
+  (set (make-local-variable 'next-error-function) #'js2-next-error)
+  (set (make-local-variable 'beginning-of-defun-function) 
#'js2-beginning-of-defun)
+  (set (make-local-variable 'end-of-defun-function) #'js2-end-of-defun)
+  ;; we un-confuse `parse-partial-sexp' by setting syntax-table properties
+  ;; for characters inside regexp literals.
+  (set (make-local-variable 'parse-sexp-lookup-properties) t)
+  ;; this is necessary to make `show-paren-function' work properly
+  (set (make-local-variable 'parse-sexp-ignore-comments) t)
+  ;; needed for M-x rgrep, among other things
+  (put 'js2-mode 'find-tag-default-function #'js2-mode-find-tag)
+
+  ;; some variables needed by cc-engine for paragraph-fill, etc.
+  (setq c-buffer-is-cc-mode t
+        c-comment-prefix-regexp js2-comment-prefix-regexp
+        c-comment-start-regexp "/[*/]\\|\\s|"
+        c-paragraph-start js2-paragraph-start
+        c-paragraph-separate "$"
+        comment-start-skip js2-comment-start-skip
+        c-syntactic-ws-start js2-syntactic-ws-start
+        c-syntactic-ws-end js2-syntactic-ws-end
+        c-syntactic-eol js2-syntactic-eol)
+
+  (setq js2-default-externs
+        (append js2-ecma-262-externs
+                (if js2-include-browser-externs
+                    js2-browser-externs)
+                (if js2-include-gears-externs
+                    js2-gears-externs)
+                (if js2-include-rhino-externs
+                     js2-rhino-externs)))
+
+  ;; We do our own syntax highlighting based on the parse tree.
+  ;; However, we want minor modes that add keywords to highlight properly
+  ;; (examples:  doxymacs, column-marker).  We do this by not letting
+  ;; font-lock unfontify anything, and telling it to fontify after we
+  ;; re-parse and re-highlight the buffer.  (We currently don't do any
+  ;; work with regions other than the whole buffer.)
+  (dolist (var '(font-lock-unfontify-buffer-function
+                 font-lock-unfontify-region-function))
+    (set (make-local-variable var) (lambda (&rest args) t)))
+
+  ;; Don't let font-lock do syntactic (string/comment) fontification.
+  (set (make-local-variable #'font-lock-syntactic-face-function)
+       (lambda (state) nil))
+
+  ;; Experiment:  make reparse-delay longer for longer files.
+  (if (plusp js2-dynamic-idle-timer-adjust)
+      (setq js2-idle-timer-delay
+            (* js2-idle-timer-delay
+               (/ (point-max) js2-dynamic-idle-timer-adjust))))
+
+  (add-hook 'change-major-mode-hook #'js2-mode-exit nil t)
+  (add-hook 'after-change-functions #'js2-mode-edit nil t)
+  (setq imenu-create-index-function #'js2-mode-create-imenu-index)
+  (imenu-add-to-menubar (concat "IM-" mode-name))
+  (when js2-mirror-mode
+    (js2-enter-mirror-mode))
+  (add-to-invisibility-spec '(js2-outline . t))
+  (set (make-local-variable 'line-move-ignore-invisible) t)
+  (set (make-local-variable 'forward-sexp-function) #'js2-mode-forward-sexp)
+  (setq js2-mode-functions-hidden nil
+        js2-mode-comments-hidden nil
+        js2-mode-buffer-dirty-p t
+        js2-mode-parsing nil)
+  (js2-reparse)
+  (run-hooks 'js2-mode-hook))
+
+(defun js2-mode-exit ()
+  "Exit `js2-mode' and clean up."
+  (interactive)
+  (when js2-mode-node-overlay
+    (delete-overlay js2-mode-node-overlay)
+    (setq js2-mode-node-overlay nil))
+  (js2-remove-overlays)
+  (setq js2-mode-ast nil)
+  (remove-hook 'change-major-mode-hook #'js2-mode-exit t)
+  (remove-from-invisibility-spec '(js2-outline . t))
+  (js2-mode-show-all)
+  (js2-with-unmodifying-text-property-changes
+    (js2-clear-face (point-min) (point-max))))
+
+(defun js2-before-save ()
+  "Clean up whitespace before saving file.
+You can disable this by customizing `js2-cleanup-whitespace'."
+  (when js2-cleanup-whitespace
+    (let ((col (current-column)))
+      (delete-trailing-whitespace)
+      ;; don't change trailing whitespace on current line
+      (unless (eq (current-column) col)
+        (indent-to col)))))
+
+(defsubst js2-mode-reset-timer ()
+  "Cancel any existing parse timer and schedule a new one."
+  (if js2-mode-parse-timer
+      (cancel-timer js2-mode-parse-timer))
+  (setq js2-mode-parsing nil)
+  (setq js2-mode-parse-timer
+        (run-with-idle-timer js2-idle-timer-delay nil #'js2-reparse)))
+
+(defun js2-mode-edit (beg end len)
+  "Schedule a new parse after buffer is edited.
+Buffer edit spans from BEG to END and is of length LEN.
+Also clears the `js2-magic' bit on autoinserted parens/brackets
+if the edit occurred on a line different from the magic paren."
+  (let* ((magic-pos (next-single-property-change (point-min) 'js2-magic))
+         (line (if magic-pos (line-number-at-pos magic-pos))))
+    (and line
+         (or (/= (line-number-at-pos beg) line)
+             (and (> 0 len)
+                  (/= (line-number-at-pos end) line)))
+         (js2-mode-mundanify-parens)))
+  (setq js2-mode-buffer-dirty-p t)
+  (js2-mode-hide-overlay)
+  (js2-mode-reset-timer))
+
+(defun js2-mode-run-font-lock ()
+  "Run `font-lock-fontify-buffer' after parsing/highlighting.
+This is intended to allow modes that install their own font-lock keywords
+to work with js2-mode.  In practice it never seems to work for long.
+Hopefully the Emacs maintainers can help figure out a way to make it work."
+  (when (and (boundp 'font-lock-keywords)
+             font-lock-keywords
+             (boundp 'font-lock-mode)
+             font-lock-mode)
+    ;; TODO:  font-lock and jit-lock really really REALLY don't want to
+    ;; play nicely with js2-mode.  They go out of their way to fail to
+    ;; provide any option for saying "look, fontify the farging buffer
+    ;; with just the keywords already".  Argh.
+    (setq font-lock-defaults (list font-lock-keywords 'keywords-only))
+    (let (font-lock-verbose)
+      (font-lock-fontify-buffer))))
+
+(defun js2-reparse (&optional force)
+  "Re-parse current buffer after user finishes some data entry.
+If we get any user input while parsing, including cursor motion,
+we discard the parse and reschedule it.  If FORCE is nil, then the
+buffer will only rebuild its `js2-mode-ast' if the buffer is dirty."
+  (let (time
+        interrupted-p
+        (js2-compiler-strict-mode js2-mode-show-strict-warnings))
+    (unless js2-mode-parsing
+      (setq js2-mode-parsing t)
+      (unwind-protect
+          (when (or js2-mode-buffer-dirty-p force)
+            (js2-remove-overlays)
+            (js2-with-unmodifying-text-property-changes
+              (remove-text-properties (point-min) (point-max) '(syntax-table))
+              (setq js2-mode-buffer-dirty-p nil
+                    js2-mode-fontifications nil
+                    js2-mode-deferred-properties nil
+                    js2-additional-externs nil)
+              (if js2-mode-verbose-parse-p
+                  (message "parsing..."))
+              (setq time
+                    (js2-time
+                     (setq interrupted-p
+                           (catch 'interrupted
+                             (setq js2-mode-ast (js2-parse))
+                             (when (plusp js2-highlight-level)
+                               (js2-mode-fontify-regions))
+                             (js2-mode-remove-suppressed-warnings)
+                             (js2-mode-show-warnings)
+                             (js2-mode-show-errors)
+                             (js2-mode-run-font-lock)  ; note:  doesn't work
+                             (js2-mode-highlight-magic-parens)
+                             (if (>= js2-highlight-level 1)
+                                 (js2-highlight-jsdoc js2-mode-ast))
+                             nil))))
+              (if interrupted-p
+                  (progn
+                    ;; unfinished parse => try again
+                    (setq js2-mode-buffer-dirty-p t)
+                    (js2-mode-reset-timer))
+                (if js2-mode-verbose-parse-p
+                    (message "Parse time: %s" time)))))
+        (setq js2-mode-parsing nil)
+        (unless interrupted-p
+          (setq js2-mode-parse-timer nil))))))
+
+(defun js2-mode-show-node ()
+  "Debugging aid:  highlight selected AST node on mouse click."
+  (interactive)
+  (let ((node (js2-node-at-point))
+        beg
+        end)
+    (when js2-mode-show-overlay
+      (if (null node)
+          (message "No node found at location %s" (point))
+        (setq beg (js2-node-abs-pos node)
+              end (+ beg (js2-node-len node)))
+        (if js2-mode-node-overlay
+            (move-overlay js2-mode-node-overlay beg end)
+          (setq js2-mode-node-overlay (make-overlay beg end))
+          (overlay-put js2-mode-node-overlay 'face 'highlight))
+        (js2-with-unmodifying-text-property-changes
+          (put-text-property beg end 'point-left #'js2-mode-hide-overlay))
+        (message "%s, parent: %s"
+                 (js2-node-short-name node)
+                 (if (js2-node-parent node)
+                     (js2-node-short-name (js2-node-parent node))
+                   "nil"))))))
+
+(defun js2-mode-hide-overlay (&optional p1 p2)
+  "Remove the debugging overlay when the point moves.
+P1 and P2 are the old and new values of point, respectively."
+  (when js2-mode-node-overlay
+    (let ((beg (overlay-start js2-mode-node-overlay))
+          (end (overlay-end js2-mode-node-overlay)))
+      ;; Sometimes we're called spuriously.
+      (unless (and p2
+                   (>= p2 beg)
+                   (<= p2 end))
+        (js2-with-unmodifying-text-property-changes
+          (remove-text-properties beg end '(point-left nil)))
+        (delete-overlay js2-mode-node-overlay)
+        (setq js2-mode-node-overlay nil)))))
+
+(defun js2-mode-reset ()
+  "Debugging helper:  reset everything."
+  (interactive)
+  (js2-mode-exit)
+  (js2-mode))
+
+(defsubst js2-mode-show-warn-or-err (e face)
+  "Highlight a warning or error E with FACE.
+E is a list of ((MSG-KEY MSG-ARG) BEG END)."
+  (let* ((key (first e))
+         (beg (second e))
+         (end (+ beg (third e)))
+         ;; Don't inadvertently go out of bounds.
+         (beg (max (point-min) (min beg (point-max))))
+         (end (max (point-min) (min end (point-max))))
+         (js2-highlight-level 3)    ; so js2-set-face is sure to fire
+         (ovl (make-overlay beg end)))
+    (overlay-put ovl 'face face)
+    (overlay-put ovl 'js2-error t)
+    (put-text-property beg end 'help-echo (js2-get-msg key))
+    (put-text-property beg end 'point-entered #'js2-echo-error)))
+
+(defun js2-remove-overlays ()
+  "Remove overlays from buffer that have a `js2-error' property."
+  (let ((beg (point-min))
+        (end (point-max)))
+    (save-excursion
+      (dolist (o (overlays-in beg end))
+        (when (overlay-get o 'js2-error)
+          (delete-overlay o))))))
+
+(defun js2-error-at-point (&optional pos)
+  "Return non-nil if there's an error overlay at POS.
+Defaults to point."
+  (loop with pos = (or pos (point))
+        for o in (overlays-at pos)
+        thereis (overlay-get o 'js2-error)))
+
+(defun js2-mode-fontify-regions ()
+  "Apply fontifications recorded during parsing."
+  ;; We defer clearing faces as long as possible to eliminate flashing.
+  (js2-clear-face (point-min) (point-max))
+  ;; have to reverse the recorded fontifications so that errors and
+  ;; warnings overwrite the normal fontifications
+  (dolist (f (nreverse js2-mode-fontifications))
+    (put-text-property (first f) (second f) 'face (third f)))
+  (setq js2-mode-fontifications nil)
+  (dolist (p js2-mode-deferred-properties)
+    (apply #'put-text-property p))
+  (setq js2-mode-deferred-properties nil))
+
+(defun js2-mode-show-errors ()
+  "Highlight syntax errors."
+  (when js2-mode-show-parse-errors
+    (dolist (e (js2-ast-root-errors js2-mode-ast))
+      (js2-mode-show-warn-or-err e 'js2-error-face))))
+
+(defun js2-mode-remove-suppressed-warnings ()
+  "Take suppressed warnings out of the AST warnings list.
+This ensures that the counts and `next-error' are correct."
+  (setf (js2-ast-root-warnings js2-mode-ast)
+        (js2-delete-if
+         (lambda (e)
+           (let ((key (caar e)))
+             (or
+              (and (not js2-strict-trailing-comma-warning)
+                   (string-match "trailing\\.comma" key))
+              (and (not js2-strict-cond-assign-warning)
+                   (string= key "msg.equal.as.assign"))
+              (and js2-missing-semi-one-line-override
+                   (string= key "msg.missing.semi")
+                   (let* ((beg (second e))
+                          (node (js2-node-at-point beg))
+                          (fn (js2-mode-find-parent-fn node))
+                          (body (and fn (js2-function-node-body fn)))
+                          (lc (and body (js2-node-abs-pos body)))
+                          (rc (and lc (+ lc (js2-node-len body)))))
+                     (and fn
+                          (or (null body)
+                              (save-excursion
+                                (goto-char beg)
+                                (and (js2-same-line lc)
+                                     (js2-same-line rc))))))))))
+         (js2-ast-root-warnings js2-mode-ast))))
+
+(defun js2-mode-show-warnings ()
+  "Highlight strict-mode warnings."
+  (when js2-mode-show-strict-warnings
+    (dolist (e (js2-ast-root-warnings js2-mode-ast))
+      (js2-mode-show-warn-or-err e 'js2-warning-face))))
+
+(defun js2-echo-error (old-point new-point)
+  "Called by point-motion hooks."
+  (let ((msg (get-text-property new-point 'help-echo)))
+    (if msg
+        (message msg))))
+
+(defalias #'js2-echo-help #'js2-echo-error)
+
+(defun js2-enter-key ()
+  "Handle user pressing the Enter key."
+  (interactive)
+  (let ((parse-status (save-excursion
+                        (parse-partial-sexp (point-min) (point)))))
+    (cond
+     ;; check if we're inside a string
+     ((nth 3 parse-status)
+      (js2-mode-split-string parse-status))
+     ;; check if inside a block comment
+     ((nth 4 parse-status)
+      (js2-mode-extend-comment))
+     (t
+      ;; should probably figure out what the mode-map says we should do
+      (if js2-indent-on-enter-key
+          (let ((js2-bounce-indent-p nil))
+            (js2-indent-line)))
+      (insert "\n")
+      (if js2-enter-indents-newline
+          (let ((js2-bounce-indent-p nil))
+            (js2-indent-line)))))))
+
+(defun js2-mode-split-string (parse-status)
+  "Turn a newline in mid-string into a string concatenation.
+PARSE-STATUS is as documented in `parse-partial-sexp'."
+  (let* ((col (current-column))
+         (quote-char (nth 3 parse-status))
+         (quote-string (string quote-char))
+         (string-beg (nth 8 parse-status))
+         (indent (save-match-data
+                   (or
+                    (save-excursion
+                      (back-to-indentation)
+                      (if (looking-at "\\+")
+                          (current-column)))
+                    (save-excursion
+                      (goto-char string-beg)
+                      (if (looking-back "\\+\\s-+")
+                          (goto-char (match-beginning 0)))
+                      (current-column))))))
+    (insert quote-char "\n")
+    (indent-to indent)
+    (insert "+ " quote-string)
+    (when (eolp)
+      (insert quote-string)
+      (backward-char 1))))
+
+(defun js2-mode-extend-comment ()
+  "When inside a comment block, add comment prefix."
+  (let (star single col first-line needs-close)
+    (save-excursion
+      (back-to-indentation)
+      (cond
+       ((looking-at "\\*[^/]")
+        (setq star t
+              col (current-column)))
+       ((looking-at "/\\*")
+        (setq star t
+              first-line t
+              col (1+ (current-column))))
+       ((looking-at "//")
+        (setq single t
+              col (current-column)))))
+    ;; Heuristic for whether we need to close the comment:
+    ;; if we've got a parse error here, assume it's an unterminated
+    ;; comment.
+    (setq needs-close
+          (or
+           (eq (get-text-property (1- (point)) 'point-entered)
+               'js2-echo-error)
+           ;; The heuristic above doesn't work well when we're
+           ;; creating a comment and there's another one downstream,
+           ;; as our parser thinks this one ends at the end of the
+           ;; next one.  (You can have a /* inside a js block comment.)
+           ;; So just close it if the next non-ws char isn't a *.
+           (and first-line
+                (eolp)
+                (save-excursion
+                  (skip-chars-forward " \t\r\n")
+                  (not (eq (char-after) ?*))))))
+    (insert "\n")
+    (cond
+     (star
+      (indent-to col)
+      (insert "* ")
+      (if (and first-line needs-close)
+          (save-excursion
+            (insert "\n")
+            (indent-to col)
+            (insert "*/"))))
+     (single
+      (when (save-excursion
+              (and (zerop (forward-line 1))
+                   (looking-at "\\s-*//")))
+        (indent-to col)
+        (insert "// "))))))
+
+(defun js2-beginning-of-line ()
+  "Toggles point between bol and first non-whitespace char in line.
+Also moves past comment delimiters when inside comments."
+  (interactive)
+  (let (node beg)
+    (cond
+     ((bolp)
+      (back-to-indentation))
+     ((looking-at "//")
+      (skip-chars-forward "/ \t"))
+     ((and (eq (char-after) ?*)
+           (setq node (js2-comment-at-point))
+           (memq (js2-comment-node-format node) '(jsdoc block))
+           (save-excursion
+             (skip-chars-backward " \t")
+             (bolp)))
+      (skip-chars-forward "\* \t"))
+     (t
+      (goto-char (point-at-bol))))))
+
+(defun js2-end-of-line ()
+  "Toggles point between eol and last non-whitespace char in line."
+  (interactive)
+  (if (eolp)
+      (skip-chars-backward " \t")
+    (goto-char (point-at-eol))))
+
+(defun js2-enter-mirror-mode()
+  "Turns on mirror mode, where quotes, brackets etc are mirrored automatically
+  on insertion."
+  (interactive)
+  (define-key js2-mode-map (read-kbd-macro "{")  'js2-mode-match-curly)
+  (define-key js2-mode-map (read-kbd-macro "}")  'js2-mode-magic-close-paren)
+  (define-key js2-mode-map (read-kbd-macro "\"") 'js2-mode-match-double-quote)
+  (define-key js2-mode-map (read-kbd-macro "'")  'js2-mode-match-single-quote)
+  (define-key js2-mode-map (read-kbd-macro "(")  'js2-mode-match-paren)
+  (define-key js2-mode-map (read-kbd-macro ")")  'js2-mode-magic-close-paren)
+  (define-key js2-mode-map (read-kbd-macro "[")  'js2-mode-match-bracket)
+  (define-key js2-mode-map (read-kbd-macro "]")  'js2-mode-magic-close-paren))
+
+(defun js2-leave-mirror-mode()
+  "Turns off mirror mode."
+  (interactive)
+  (dolist (key '("{" "\"" "'" "(" ")" "[" "]"))
+    (define-key js2-mode-map (read-kbd-macro key) 'self-insert-command)))
+
+(defsubst js2-mode-inside-string ()
+  "Return non-nil if inside a string.
+Actually returns the quote character that begins the string."
+   (let ((parse-state (save-excursion
+                        (parse-partial-sexp (point-min) (point)))))
+      (nth 3 parse-state)))
+
+(defsubst js2-mode-inside-comment-or-string ()
+  "Return non-nil if inside a comment or string."
+  (or
+   (let ((comment-start
+          (save-excursion
+            (goto-char (point-at-bol))
+            (if (re-search-forward "//" (point-at-eol) t)
+                (match-beginning 0)))))
+     (and comment-start
+          (<= comment-start (point))))
+   (let ((parse-state (save-excursion
+                        (parse-partial-sexp (point-min) (point)))))
+     (or (nth 3 parse-state)
+         (nth 4 parse-state)))))
+
+(defsubst js2-make-magic-delimiter (delim &optional pos)
+  "Add `js2-magic' and `js2-magic-paren-face' to DELIM, a string.
+Sets value of `js2-magic' text property to line number at POS."
+  (propertize delim
+              'js2-magic (line-number-at-pos pos)
+              'face 'js2-magic-paren-face))
+
+(defun js2-mode-match-delimiter (open close)
+  "Insert OPEN (a string) and possibly matching delimiter CLOSE.
+The rule we use, which as far as we can tell is how Eclipse works,
+is that we insert the match if we're not in a comment or string,
+and the next non-whitespace character is either punctuation or
+occurs on another line."
+  (insert open)
+  (when (and (looking-at "\\s-*\\([[:punct:]]\\|$\\)")
+             (not (js2-mode-inside-comment-or-string)))
+    (save-excursion
+      (insert (js2-make-magic-delimiter close)))
+    (when js2-auto-indent-p
+      (let ((js2-bounce-indent-p (js2-code-at-bol-p)))
+        (js2-indent-line)))))
+
+(defun js2-mode-match-bracket ()
+  "Insert matching bracket."
+  (interactive)
+  (js2-mode-match-delimiter "[" "]"))
+
+(defun js2-mode-match-paren ()
+  "Insert matching paren unless already inserted."
+  (interactive)
+  (js2-mode-match-delimiter "(" ")"))
+
+(defun js2-mode-match-curly (arg)
+  "Insert matching curly-brace.
+With prefix arg, no formatting or indentation will occur -- the close-brace
+is simply inserted directly at the point."
+  (interactive "p")
+  (let (try-pos)
+    (cond
+     (current-prefix-arg
+      (js2-mode-match-delimiter "{" "}"))
+     ((and js2-auto-insert-catch-block
+           (setq try-pos (if (looking-back "\\s-*\\(try\\)\\s-*"
+                                           (point-at-bol))
+                             (match-beginning 1))))
+      (js2-insert-catch-skel try-pos))
+     (t
+      ;; Otherwise try to do something smarter.
+      (insert "{")
+      (unless (or (not (looking-at "\\s-*$"))
+                  (save-excursion
+                    (skip-chars-forward " \t\r\n")
+                    (and (looking-at "}")
+                         (js2-error-at-point)))
+                  (js2-mode-inside-comment-or-string))
+        (undo-boundary)
+        ;; absolutely mystifying bug:  when inserting the next "\n",
+        ;; the buffer-undo-list is given two new entries:  the inserted range,
+        ;; and the incorrect position of the point.  It's recorded incorrectly
+        ;; as being before the opening "{", not after it.  But it's recorded
+        ;; as the correct value if you're debugging `js2-mode-match-curly'
+        ;; in edebug.  I have no idea why it's doing this, but incrementing
+        ;; the inserted position fixes the problem, so that the undo takes us
+        ;; back to just after the user-inserted "{".
+        (insert "\n")
+        (ignore-errors
+          (incf (cadr buffer-undo-list)))
+        (js2-indent-line)
+        (save-excursion
+          (insert "\n}")
+          (let ((js2-bounce-indent-p (js2-code-at-bol-p)))
+            (js2-indent-line))))))))
+
+(defun js2-insert-catch-skel (try-pos)
+  "Complete a try/catch block after inserting a { following a try keyword.
+Rationale is that a try always needs a catch or a finally, and the catch is
+the more likely of the two.
+
+TRY-POS is the buffer position of the try keyword.  The open-curly should
+already have been inserted."
+  (insert "{")
+  (let ((try-col (save-excursion
+                   (goto-char try-pos)
+                   (current-column))))
+    (insert "\n")
+    (undo-boundary)
+    (js2-indent-line) ;; indent the blank line where cursor will end up
+    (save-excursion
+      (insert "\n")
+      (indent-to try-col)
+      (insert "} catch (x) {\n\n")
+      (indent-to try-col)
+      (insert "}"))))
+
+(defun js2-mode-highlight-magic-parens ()
+  "Re-highlight magic parens after parsing nukes the 'face prop."
+  (let ((beg (point-min))
+        end)
+    (while (setq beg (next-single-property-change beg 'js2-magic))
+      (setq end (next-single-property-change (1+ beg) 'js2-magic))
+      (if (get-text-property beg 'js2-magic)
+          (js2-with-unmodifying-text-property-changes
+            (put-text-property beg (or end (1+ beg))
+                               'face 'js2-magic-paren-face))))))
+
+(defun js2-mode-mundanify-parens ()
+  "Clear all magic parens and brackets."
+  (let ((beg (point-min))
+        end)
+    (while (setq beg (next-single-property-change beg 'js2-magic))
+      (setq end (next-single-property-change (1+ beg) 'js2-magic))
+      (remove-text-properties beg (or end (1+ beg))
+                              '(js2-magic face)))))
+
+(defsubst js2-match-quote (quote-string)
+  (let ((start-quote (js2-mode-inside-string)))
+    (cond
+     ;; inside a comment - don't do quote-matching, since we can't
+     ;; reliably figure out if we're in a string inside the comment
+     ((js2-comment-at-point)
+      (insert quote-string))
+     ((not start-quote)
+      ;; not in string => insert matched quotes
+      (insert quote-string)
+      ;; exception:  if we're just before a word, don't double it.
+      (unless (looking-at "[^ \t\r\n]")
+        (save-excursion
+          (insert quote-string))))
+     ((looking-at quote-string)
+      (if (looking-back "[^\\]\\\\")
+          (insert quote-string)
+        (forward-char 1)))
+     ((and js2-mode-escape-quotes
+           (save-excursion
+             (save-match-data
+               (re-search-forward quote-string (point-at-eol) t))))
+      ;; inside terminated string, escape quote (unless already escaped)
+      (insert (if (looking-back "[^\\]\\\\")
+                  quote-string
+                (concat "\\" quote-string))))
+     (t
+      (insert quote-string)))))        ; else terminate the string
+
+(defun js2-mode-match-single-quote ()
+  "Insert matching single-quote."
+  (interactive)
+  (let ((parse-status (parse-partial-sexp (point-min) (point))))
+    ;; don't match inside comments, since apostrophe is more common
+    (if (nth 4 parse-status)
+        (insert "'")
+      (js2-match-quote "'"))))
+
+(defun js2-mode-match-double-quote ()
+  "Insert matching double-quote."
+  (interactive)
+  (js2-match-quote "\""))
+
+;; Eclipse works as follows:
+;;  * type an open-paren and it auto-inserts close-paren
+;;    - auto-inserted paren gets a green bracket
+;;    - green bracket means typing close-paren there will skip it
+;;  * if you insert any text on a different line, it turns off
+(defun js2-mode-magic-close-paren ()
+  "Skip over close-paren rather than inserting, where appropriate."
+  (interactive)
+  (let* ((here (point))
+         (parse-status (parse-partial-sexp (point-min) here))
+         (open-pos (nth 1 parse-status))
+         (close last-input-event)
+         (open (cond
+                ((eq close ?\))
+                 ?\()
+                ((eq close ?\])
+                 ?\[)
+                ((eq close ?})
+                 ?{)
+                (t nil))))
+    (if (and (eq (char-after) close)
+             (eq open (char-after open-pos))
+             (js2-same-line open-pos)
+             (get-text-property here 'js2-magic))
+        (progn
+          (remove-text-properties here (1+ here) '(js2-magic face))
+          (forward-char 1))
+      (insert-char close 1))
+    (blink-matching-open)))
+
+(defun js2-mode-wait-for-parse (callback)
+  "Invoke CALLBACK when parsing is finished.
+If parsing is already finished, calls CALLBACK immediately."
+  (if (not js2-mode-buffer-dirty-p)
+      (funcall callback)
+    (push callback js2-mode-pending-parse-callbacks)
+    (add-hook 'js2-parse-finished-hook #'js2-mode-parse-finished)))
+
+(defun js2-mode-parse-finished ()
+  "Invoke callbacks in `js2-mode-pending-parse-callbacks'."
+  ;; We can't let errors propagate up, since it prevents the
+  ;; `js2-parse' method from completing normally and returning
+  ;; the ast, which makes things mysteriously not work right.
+  (unwind-protect
+      (dolist (cb js2-mode-pending-parse-callbacks)
+        (condition-case err
+            (funcall cb)
+          (error (message "%s" err))))
+    (setq js2-mode-pending-parse-callbacks nil)))
+
+(defun js2-mode-flag-region (from to flag)
+  "Hide or show text from FROM to TO, according to FLAG.
+If FLAG is nil then text is shown, while if FLAG is t the text is hidden.
+Returns the created overlay if FLAG is non-nil."
+  (remove-overlays from to 'invisible 'js2-outline)
+  (when flag
+    (let ((o (make-overlay from to)))
+      (overlay-put o 'invisible 'js2-outline)
+      (overlay-put o 'isearch-open-invisible
+                   'js2-isearch-open-invisible)
+      o)))
+
+;; Function to be set as an outline-isearch-open-invisible' property
+;; to the overlay that makes the outline invisible (see
+;; `js2-mode-flag-region').
+(defun js2-isearch-open-invisible (overlay)
+  ;; We rely on the fact that isearch places point on the matched text.
+  (js2-mode-show-element))
+
+(defun js2-mode-invisible-overlay-bounds (&optional pos)
+  "Return cons cell of bounds of folding overlay at POS.
+Returns nil if not found."
+  (let ((overlays (overlays-at (or pos (point))))
+        o)
+    (while (and overlays
+                (not o))
+      (if (overlay-get (car overlays) 'invisible)
+          (setq o (car overlays))
+        (setq overlays (cdr overlays))))
+    (if o
+        (cons (overlay-start o) (overlay-end o)))))
+
+(defun js2-mode-function-at-point (&optional pos)
+  "Return the innermost function node enclosing current point.
+Returns nil if point is not in a function."
+  (let ((node (js2-node-at-point pos)))
+    (while (and node (not (js2-function-node-p node)))
+      (setq node (js2-node-parent node)))
+    (if (js2-function-node-p node)
+        node)))
+
+(defun js2-mode-toggle-element ()
+  "Hide or show the foldable element at the point."
+  (interactive)
+  (let (comment fn pos)
+    (save-excursion
+      (save-match-data
+        (cond
+         ;; /* ... */ comment?
+         ((js2-block-comment-p (setq comment (js2-comment-at-point)))
+          (if (js2-mode-invisible-overlay-bounds
+               (setq pos (+ 3 (js2-node-abs-pos comment))))
+              (progn
+                (goto-char pos)
+                (js2-mode-show-element))
+            (js2-mode-hide-element)))
+         ;; //-comment?
+         ((save-excursion
+            (back-to-indentation)
+            (looking-at js2-mode-//-comment-re))
+          (js2-mode-toggle-//-comment))
+         ;; function?
+         ((setq fn (js2-mode-function-at-point))
+          (setq pos (and (js2-function-node-body fn)
+                         (js2-node-abs-pos (js2-function-node-body fn))))
+          (goto-char (1+ pos))
+          (if (js2-mode-invisible-overlay-bounds)
+              (js2-mode-show-element)
+            (js2-mode-hide-element)))
+         (t
+          (message "Nothing at point to hide or show")))))))
+
+(defun js2-mode-hide-element ()
+  "Fold/hide contents of a block, showing ellipses.
+Show the hidden text with \\[js2-mode-show-element]."
+  (interactive)
+  (if js2-mode-buffer-dirty-p
+      (js2-mode-wait-for-parse #'js2-mode-hide-element))
+  (let (node body beg end)
+    (cond
+     ((js2-mode-invisible-overlay-bounds)
+      (message "already hidden"))
+     (t
+      (setq node (js2-node-at-point))
+      (cond
+       ((js2-block-comment-p node)
+        (js2-mode-hide-comment node))
+       (t
+        (while (and node (not (js2-function-node-p node)))
+          (setq node (js2-node-parent node)))
+        (if (and node
+                 (setq body (js2-function-node-body node)))
+            (progn
+              (setq beg (js2-node-abs-pos body)
+                    end (+ beg (js2-node-len body)))
+              (js2-mode-flag-region (1+ beg) (1- end) 'hide))
+          (message "No collapsable element found at point"))))))))
+
+(defun js2-mode-show-element ()
+  "Show the hidden element at current point."
+  (interactive)
+  (let ((bounds (js2-mode-invisible-overlay-bounds)))
+    (if bounds
+        (js2-mode-flag-region (car bounds) (cdr bounds) nil)
+      (message "Nothing to un-hide"))))
+
+(defun js2-mode-show-all ()
+  "Show all of the text in the buffer."
+  (interactive)
+  (js2-mode-flag-region (point-min) (point-max) nil))
+
+(defun js2-mode-toggle-hide-functions ()
+  (interactive)
+  (if js2-mode-functions-hidden
+      (js2-mode-show-functions)
+    (js2-mode-hide-functions)))
+
+(defun js2-mode-hide-functions ()
+  "Hides all non-nested function bodies in the buffer.
+Use \\[js2-mode-show-all] to reveal them, or \\[js2-mode-show-element]
+to open an individual entry."
+  (interactive)
+  (if js2-mode-buffer-dirty-p
+      (js2-mode-wait-for-parse #'js2-mode-hide-functions))
+  (if (null js2-mode-ast)
+      (message "Oops - parsing failed")
+    (setq js2-mode-functions-hidden t)
+    (js2-visit-ast js2-mode-ast #'js2-mode-function-hider)))
+
+(defun js2-mode-function-hider (n endp)
+  (when (not endp)
+    (let ((tt (js2-node-type n))
+          body beg end)
+      (cond
+       ((and (= tt js2-FUNCTION)
+             (setq body (js2-function-node-body n)))
+        (setq beg (js2-node-abs-pos body)
+              end (+ beg (js2-node-len body)))
+        (js2-mode-flag-region (1+ beg) (1- end) 'hide)
+        nil)   ; don't process children of function
+       (t
+        t))))) ; keep processing other AST nodes
+
+(defun js2-mode-show-functions ()
+  "Un-hide any folded function bodies in the buffer."
+  (interactive)
+  (setq js2-mode-functions-hidden nil)
+  (save-excursion
+    (goto-char (point-min))
+    (while (/= (goto-char (next-overlay-change (point)))
+               (point-max))
+      (dolist (o (overlays-at (point)))
+        (when (and (overlay-get o 'invisible)
+                   (not (overlay-get o 'comment)))
+          (js2-mode-flag-region (overlay-start o) (overlay-end o) nil))))))
+
+(defun js2-mode-hide-comment (n)
+  (let* ((head (if (eq (js2-comment-node-format n) 'jsdoc)
+                   3  ; /**
+                 2))  ; /*
+         (beg (+ (js2-node-abs-pos n) head))
+         (end (- (+ beg (js2-node-len n)) head 2))
+         (o (js2-mode-flag-region beg end 'hide)))
+    (overlay-put o 'comment t)))
+
+(defun js2-mode-toggle-hide-comments ()
+  "Folds all block comments in the buffer.
+Use \\[js2-mode-show-all] to reveal them, or \\[js2-mode-show-element]
+to open an individual entry."
+  (interactive)
+  (if js2-mode-comments-hidden
+      (js2-mode-show-comments)
+    (js2-mode-hide-comments)))
+
+(defun js2-mode-hide-comments ()
+  (interactive)
+  (if js2-mode-buffer-dirty-p
+      (js2-mode-wait-for-parse #'js2-mode-hide-comments))
+  (if (null js2-mode-ast)
+      (message "Oops - parsing failed")
+    (setq js2-mode-comments-hidden t)
+    (dolist (n (js2-ast-root-comments js2-mode-ast))
+      (let ((format (js2-comment-node-format n)))
+        (when (js2-block-comment-p n)
+          (js2-mode-hide-comment n))))
+    (js2-mode-hide-//-comments)))
+
+(defsubst js2-mode-extend-//-comment (direction)
+  "Find start or end of a block of similar //-comment lines.
+DIRECTION is -1 to look back, 1 to look forward.
+INDENT is the indentation level to match.
+Returns the end-of-line position of the furthest adjacent
+//-comment line with the same indentation as the current line.
+If there is no such matching line, returns current end of line."
+  (let ((pos (point-at-eol))
+        (indent (current-indentation)))
+    (save-excursion
+      (save-match-data
+        (while (and (zerop (forward-line direction))
+                    (looking-at js2-mode-//-comment-re)
+                    (eq indent (length (match-string 1))))
+          (setq pos (point-at-eol)))
+      pos))))
+
+(defun js2-mode-hide-//-comments ()
+  "Fold adjacent 1-line comments, showing only snippet of first one."
+  (let (beg end)
+    (save-excursion
+      (save-match-data
+        (goto-char (point-min))
+        (while (re-search-forward js2-mode-//-comment-re nil t)
+          (setq beg (point)
+                end (js2-mode-extend-//-comment 1))
+          (unless (eq beg end)
+            (overlay-put (js2-mode-flag-region beg end 'hide)
+                         'comment t))
+          (goto-char end)
+          (forward-char 1))))))
+
+(defun js2-mode-toggle-//-comment ()
+  "Fold or un-fold any multi-line //-comment at point.
+Caller should have determined that this line starts with a //-comment."
+  (let* ((beg (point-at-eol))
+         (end beg))
+    (save-excursion
+      (goto-char end)
+      (if (js2-mode-invisible-overlay-bounds)
+          (js2-mode-show-element)
+        ;; else hide the comment
+        (setq beg (js2-mode-extend-//-comment -1)
+              end (js2-mode-extend-//-comment 1))
+        (unless (eq beg end)
+          (overlay-put (js2-mode-flag-region beg end 'hide)
+                       'comment t))))))
+
+(defun js2-mode-show-comments ()
+  "Un-hide any hidden comments, leaving other hidden elements alone."
+  (interactive)
+  (setq js2-mode-comments-hidden nil)
+  (save-excursion
+    (goto-char (point-min))
+    (while (/= (goto-char (next-overlay-change (point)))
+               (point-max))
+      (dolist (o (overlays-at (point)))
+        (when (overlay-get o 'comment)
+          (js2-mode-flag-region (overlay-start o) (overlay-end o) nil))))))
+
+(defun js2-mode-display-warnings-and-errors ()
+  "Turn on display of warnings and errors."
+  (interactive)
+  (setq js2-mode-show-parse-errors t
+        js2-mode-show-strict-warnings t)
+  (js2-reparse 'force))
+
+(defun js2-mode-hide-warnings-and-errors ()
+  "Turn off display of warnings and errors."
+  (interactive)
+  (setq js2-mode-show-parse-errors nil
+        js2-mode-show-strict-warnings nil)
+  (js2-reparse 'force))
+
+(defun js2-mode-toggle-warnings-and-errors ()
+  "Toggle the display of warnings and errors.
+Some users don't like having warnings/errors reported while they type."
+  (interactive)
+  (setq js2-mode-show-parse-errors (not js2-mode-show-parse-errors)
+        js2-mode-show-strict-warnings (not js2-mode-show-strict-warnings))
+  (if (interactive-p)
+      (message "warnings and errors %s"
+               (if js2-mode-show-parse-errors
+                   "enabled"
+                 "disabled")))
+  (js2-reparse 'force))
+
+(defun js2-mode-customize ()
+  (interactive)
+  (customize-group 'js2-mode))
+
+(defun js2-mode-forward-sexp (&optional arg)
+  "Move forward across one statement or balanced expression.
+With ARG, do it that many times.  Negative arg -N means
+move backward across N balanced expressions."
+  (interactive "p")
+  (setq arg (or arg 1))
+  (if js2-mode-buffer-dirty-p
+      (js2-mode-wait-for-parse #'js2-mode-forward-sexp))
+  (let (node end (start (point)))
+    (cond
+     ;; backward-sexp
+     ;; could probably make this better for some cases:
+     ;;  - if in statement block (e.g. function body), go to parent
+     ;;  - infix exprs like (foo in bar) - maybe go to beginning
+     ;;    of infix expr if in the right-side expression?
+     ((and arg (minusp arg))
+      (dotimes (i (- arg))
+        (js2-backward-sws)
+        (forward-char -1)  ; enter the node we backed up to
+        (setq node (js2-node-at-point (point) t))
+        (goto-char (if node
+                       (js2-node-abs-pos node)
+                     (point-min)))))
+    (t
+     ;; forward-sexp
+     (js2-forward-sws)
+     (dotimes (i arg)
+       (js2-forward-sws)
+       (setq node (js2-node-at-point (point) t)
+             end (if node (+ (js2-node-abs-pos node)
+                             (js2-node-len node))))
+       (goto-char (or end (point-max))))))))
+
+(defun js2-next-error (&optional arg reset)
+  "Move to next parse error.
+Typically invoked via \\[next-error].
+ARG is the number of errors, forward or backward, to move.
+RESET means start over from the beginning."
+  (interactive "p")
+  (if (or (null js2-mode-ast)
+          (and (null (js2-ast-root-errors js2-mode-ast))
+               (null (js2-ast-root-warnings js2-mode-ast))))
+      (message "No errors")
+    (when reset
+      (goto-char (point-min)))
+    (let* ((errs (copy-sequence
+                  (append (js2-ast-root-errors js2-mode-ast)
+                          (js2-ast-root-warnings js2-mode-ast))))
+           (continue t)
+           (start (point))
+           (count (or arg 1))
+           (backward (minusp count))
+           (sorter (if backward '> '<))
+           (stopper (if backward '< '>))
+           (count (abs count))
+           all-errs
+           err)
+      ;; sort by start position
+      (setq errs (sort errs (lambda (e1 e2)
+                              (funcall sorter (second e1) (second e2))))
+            all-errs errs)
+      ;; find nth error with pos > start
+      (while (and errs continue)
+        (when (funcall stopper (cadar errs) start)
+          (setq err (car errs))
+          (if (zerop (decf count))
+              (setq continue nil)))
+        (setq errs (cdr errs)))
+      (if err
+          (goto-char (second err))
+        ;; wrap around to first error
+        (goto-char (second (car all-errs)))
+        ;; if we were already on it, echo msg again
+        (if (= (point) start)
+            (js2-echo-error (point) (point)))))))
+
+(defun js2-down-mouse-3 ()
+  "Make right-click move the point to the click location.
+This makes right-click context menu operations a bit more intuitive.
+The point will not move if the region is active, however, to avoid
+destroying the region selection."
+  (interactive)
+  (when (and js2-move-point-on-right-click
+             (not mark-active))
+    (let ((e last-input-event))
+      (ignore-errors
+        (goto-char (cadadr e))))))
+
+(defun js2-mode-create-imenu-index ()
+  "Return an alist for `imenu--index-alist'."
+  ;; This is built up in `js2-parse-record-imenu' during parsing.
+  (when js2-mode-ast
+    ;; if we have an ast but no recorder, they're requesting a rescan
+    (unless js2-imenu-recorder
+      (js2-reparse 'force))
+    (prog1
+        (js2-build-imenu-index)
+      (setq js2-imenu-recorder nil
+            js2-imenu-function-map nil))))
+
+(defun js2-mode-find-tag ()
+  "Replacement for `find-tag-default'.
+`find-tag-default' returns a ridiculous answer inside comments."
+  (let (beg end)
+    (js2-with-underscore-as-word-syntax
+      (save-excursion
+        (if (and (not (looking-at "[A-Za-z0-9_$]"))
+                 (looking-back "[A-Za-z0-9_$]"))
+            (setq beg (progn (forward-word -1) (point))
+                  end (progn (forward-word 1) (point)))
+          (setq beg (progn (forward-word 1) (point))
+                end (progn (forward-word -1) (point))))
+        (replace-regexp-in-string
+         "[\"']" ""
+         (buffer-substring-no-properties beg end))))))
+
+(defun js2-mode-forward-sibling ()
+  "Move to the end of the sibling following point in parent.
+Returns non-nil if successful, or nil if there was no following sibling."
+  (let* ((node (js2-node-at-point))
+         (parent (js2-mode-find-enclosing-fn node))
+         sib)
+    (when (setq sib (js2-node-find-child-after (point) parent))
+      (goto-char (+ (js2-node-abs-pos sib)
+                    (js2-node-len sib))))))
+
+(defun js2-mode-backward-sibling ()
+  "Move to the beginning of the sibling node preceding point in parent.
+Parent is defined as the enclosing script or function."
+  (let* ((node (js2-node-at-point))
+         (parent (js2-mode-find-enclosing-fn node))
+         sib)
+    (when (setq sib (js2-node-find-child-before (point) parent))
+      (goto-char (js2-node-abs-pos sib)))))
+
+(defun js2-beginning-of-defun ()
+  "Go to line on which current function starts, and return non-nil.
+If we're not in a function, go to beginning of previous script-level element."
+  (interactive)
+  (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point)))
+        pos sib)
+    (cond
+     ((and (js2-function-node-p parent)
+           (not (eq (point) (setq pos (js2-node-abs-pos parent)))))
+      (goto-char pos))
+     (t
+      (js2-mode-backward-sibling)))))
+
+(defun js2-end-of-defun ()
+  "Go to the char after the last position of the current function.
+If we're not in a function, skips over the next script-level element."
+  (interactive)
+  (let ((parent (js2-node-parent-script-or-fn (js2-node-at-point))))
+    (if (not (js2-function-node-p parent))
+        ;; punt:  skip over next script-level element beyond point
+        (js2-mode-forward-sibling)
+      (goto-char (+ 1 (+ (js2-node-abs-pos parent)
+                         (js2-node-len parent)))))))
+
+(defun js2-mark-defun (&optional allow-extend)
+  "Put mark at end of this function, point at beginning.
+The function marked is the one that contains point.
+
+Interactively, if this command is repeated,
+or (in Transient Mark mode) if the mark is active,
+it marks the next defun after the ones already marked."
+  (interactive "p")
+  (let (extended)
+    (when (and allow-extend
+               (or (and (eq last-command this-command) (mark t))
+                   (and transient-mark-mode mark-active)))
+      (let ((sib (save-excursion
+                   (goto-char (mark))
+                   (if (js2-mode-forward-sibling)
+                       (point))))
+            node)
+        (if sib
+            (progn
+              (set-mark sib)
+              (setq extended t))
+          ;; no more siblings - try extending to enclosing node
+          (goto-char (mark t)))))
+   (when (not extended)
+     (let ((node (js2-node-at-point (point) t)) ; skip comments
+           ast fn stmt parent beg end)
+       (when (js2-ast-root-p node)
+         (setq ast node
+               node (or (js2-node-find-child-after (point) node)
+                        (js2-node-find-child-before (point) node))))
+       ;; only mark whole buffer if we can't find any children
+       (if (null node)
+           (setq node ast))
+       (if (js2-function-node-p node)
+           (setq parent node)
+         (setq fn (js2-mode-find-enclosing-fn node)
+               stmt (if (or (null fn)
+                            (js2-ast-root-p fn))
+                        (js2-mode-find-first-stmt node))
+               parent (or stmt fn)))
+       (setq beg (js2-node-abs-pos parent)
+             end (+ beg (js2-node-len parent)))
+       (push-mark beg)
+       (goto-char end)
+       (exchange-point-and-mark)))))
+
+(defun js2-narrow-to-defun ()
+  "Narrow to the function enclosing point."
+  (interactive)
+  (let* ((node (js2-node-at-point (point) t))  ; skip comments
+         (fn (if (js2-script-node-p node)
+                 node
+               (js2-mode-find-enclosing-fn node)))
+         (beg (js2-node-abs-pos fn)))
+    (unless (js2-ast-root-p fn)
+      (narrow-to-region beg (+ beg (js2-node-len fn))))))
+
+(provide 'js2-mode)
+
+;;; js2-mode.el ends here

commit 7deb27ca53df3f317755664e25f95dcc9eabdb1f
Author: Thierry Volpiatto <address@hidden>
Date:   Thu Mar 11 09:04:46 2010 +0100

    Refactorize, add scroll-other-window to keymap.
    
    (ioccur-scroll-other-window-up, ioccur-scroll-other-window-down): new.

diff --git a/ioccur.el b/ioccur.el
index 02538b3..2b0e5e9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -43,6 +43,8 @@
     (define-key map (kbd "RET") 'ioccur-jump-and-quit)
     (define-key map (kbd "<C-down>") 'ioccur-scroll-down)
     (define-key map (kbd "<C-up>") 'ioccur-scroll-up)
+    (define-key map (kbd "C-v") 'ioccur-scroll-other-window-up)
+    (define-key map (kbd "M-v") 'ioccur-scroll-other-window-down)
     (define-key map (kbd "<down>") 'ioccur-next-line)
     (define-key map (kbd "<up>") 'ioccur-precedent-line)
     (define-key map (kbd "C-n") 'ioccur-next-line)
@@ -187,8 +189,8 @@ Special commands:
                    (setq iterator (ioccur-iter-list sub))
                    (ioccur-iter-next iterator)))))))
 
-(defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'file))
-  "Return an alist of all the (num-line line) of a file or buffer BFILE 
matching REGEXP."
+(defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'buffer))
+  "Return an alist of all the (numline line)  matching REGEXP."
   (let ((count 0)
         (fn    (case insert-fn
                  ('file 'insert-file-contents)
@@ -206,11 +208,12 @@ Special commands:
 (defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))
   "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
-  (let ((matched-lines (ioccur-find-readlines buffer regex :insert-fn 
'buffer)))
+  (let ((matched-lines (ioccur-find-readlines buffer regex)))
     (when matched-lines
       (dolist (i matched-lines) ; Each element is of the form '(key value)
         (let* ((ltp           (second i))
-               (replace-reg   (if (string-match "^\t" ltp) "\\(^\t*\\)" "\\(^ 
*\\)"))
+               (replace-reg   (if (string-match "^\t" ltp)
+                                  "\\(^\t*\\)" "\\(^ *\\)"))
                (new-ltp       (replace-regexp-in-string replace-reg "" ltp))
                (line-to-print new-ltp))
           (incf ioccur-count-occurences)
@@ -279,6 +282,16 @@ Special commands:
     (when ioccur-match-overlay
       (delete-overlay ioccur-match-overlay))))
 
+(defun ioccur-scroll-other-window-down ()
+  "Scroll other window down."
+  (interactive)
+  (scroll-other-window 1))
+
+(defun ioccur-scroll-other-window-up ()
+  "Scroll other window up."
+  (interactive)
+  (scroll-other-window -1))
+
 (defun ioccur-scroll (n)
   "Scroll other buffer and move overlay accordingly."
   (ioccur-forward-line n)
@@ -299,7 +312,7 @@ Special commands:
   (ioccur-scroll -1))
 
 (defun ioccur-read-char-or-event (prompt)
-  "Read keyboard input with `read-char' and `read-event' if `read-key' not 
available."
+  "Replace `read-key' when  not available."
   (if (fboundp 'read-key)
       (read-key prompt)
       (let* ((chr (condition-case nil (read-char prompt) (error nil)))
@@ -308,7 +321,8 @@ Special commands:
 
 (defun ioccur-read-search-input (initial-input start-point)
   "Read each keyboard input and add it to `ioccur-search-pattern'."
-  (let* ((prompt         (propertize ioccur-search-prompt 'face 
'minibuffer-prompt))
+  (let* ((prompt         (propertize ioccur-search-prompt
+                                     'face 'minibuffer-prompt))
          (inhibit-quit   (not (fboundp 'read-key)))
          (tmp-list       ())
          (it-prec        nil)
@@ -348,11 +362,13 @@ Special commands:
                          (let ((it (or it-prec it-next)))
                            (setq cur-hist-elm (ioccur-iter-next it))
                            (setq tmp-list nil)
-                           (loop for char across cur-hist-elm do (push char 
tmp-list))
+                           (loop for char across cur-hist-elm
+                              do (push char tmp-list))
                            (setq ioccur-search-pattern cur-hist-elm)))
                        ;; First call use car of history ring.
                        (setq tmp-list nil)
-                       (loop for char across cur-hist-elm do (push char 
tmp-list))
+                       (loop for char across cur-hist-elm
+                          do (push char tmp-list))
                        (setq ioccur-search-pattern cur-hist-elm)
                        (setq start-hist t)))
                  (message "No history available.") (sit-for 2) t))
@@ -372,63 +388,64 @@ Special commands:
                (unless (or (equal char ?\M-p) (equal char ?\M-n))
                  (setq start-hist nil) (setq cur-hist-elm (car 
ioccur-history)))
                (case char
-                 ((down ?\C-n)                 ; Next line.
+                 ((down ?\C-n)       ; Next line.
                   (stop-timer) (ioccur-next-line)
                   (ioccur-color-current-line) t)
-                 ((up ?\C-p)                   ; Precedent line.
+                 ((up ?\C-p)         ; Precedent line.
                   (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
-                 (C-down                       ; Scroll both windows down.
+                 (C-down             ; Scroll both windows down.
                   (stop-timer)
                   (ioccur-scroll-down) t)
-                 (C-up                         ; Scroll both windows up.
+                 (C-up               ; Scroll both windows up.
                   (stop-timer) (ioccur-scroll-up) t)
-                 ((?\e ?\r) (message nil) nil) ; RET or ESC break and exit 
code.
-                 (?\d                          ; Delete backward with DEL.
+                 ((?\e ?\r)          ; RET or ESC break and exit code.
+                  (message nil) nil)
+                 (?\d                ; Delete backward with DEL.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
                   (pop tmp-list) t)
-                 (?\C-g                        ; Quit and restore buffers.
+                 (?\C-g              ; Quit and restore buffers.
                   (setq ioccur-quit-flag t) nil)
-                 ((or right ?\C-z)             ; Persistent action.
+                 ((or right ?\C-z)   ; Persistent action.
                   (ioccur-jump) (other-window 1) t)
-                 ((left ?\C-j)                 ; Jump to candidate and kill 
search buffer.
+                 ((left ?\C-j)       ; Jump to candidate and kill search 
buffer.
                   (setq ioccur-exit-and-quit-p t) nil)
-                 (?\C-v                        ; Scroll down.
-                  (scroll-other-window 1) t)
-                 (?\M-v                        ; Scroll up.
-                  (scroll-other-window -1) t)
-                 (?\C-k                        ; Kill input.
+                 (?\C-v              ; Scroll down.
+                  (ioccur-scroll-other-window-down) t)
+                 (?\M-v              ; Scroll up.
+                  (ioccur-scroll-other-window-up) t)
+                 (?\C-k              ; Kill input.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
                   (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
-                 (?\C-w                        ; Yank stuff at point.
+                 (?\C-w              ; Yank stuff at point.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (unless old-yank-point (setq old-yank-point (point)))
                     (setq yank-point (point)) (forward-word 1)
                     (setq initial-input (buffer-substring yank-point (point))))
                   (unless (string= initial-input "")
-                    (loop for char across initial-input do (push char 
tmp-list)))
+                    (loop for char across initial-input
+                       do (push char tmp-list)))
                   (setq ioccur-search-pattern initial-input) t)
-                 (?\M-p                        ; Precedent history elm.
+                 (?\M-p              ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))
-                 (?\M-n                        ; Next history elm.
+                 (?\M-n              ; Next history elm.
                   (start-timer)
                   (cycle-hist 1))
-                 (t                            ; Store character.
+                 (t                  ; Store character.
                   (start-timer)
                   (if (characterp char)
                       (push char tmp-list)
-                      ;; Else, a non--character event is entered, not listed 
above.
-                      ;; add it to `unread-command-events' and exit (nil) .
                       (setq unread-command-events
-                            (nconc (mapcar 'identity 
(this-single-command-raw-keys))
+                            (nconc (mapcar 'identity
+                                           (this-single-command-raw-keys))
                                    unread-command-events))
                       nil))))
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
@@ -448,7 +465,8 @@ Special commands:
                                     'face 'underline)
                         (propertize regexp 'face 'ioccur-regexp-face)
                         (propertize
-                         (format " in %s" buffer-name) 'face 'underline) 
"\n\n"))
+                         (format " in %s" buffer-name)
+                         'face 'underline) "\n\n"))
         (ioccur-color-current-line))))
 
 

commit 79732f4c33178a61bade7835d67a953117c637aa
Author: Thierry Volpiatto <address@hidden>
Date:   Wed Mar 10 15:05:39 2010 +0100

    (ioccur-print-buffer, defun ioccur-update-buffer):Renamed functions, 
cleanup.

diff --git a/ioccur.el b/ioccur.el
index ef4e1b6..02538b3 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -126,7 +126,8 @@ Special commands:
     (if ioccur-mode-line-string
         (setq mode-line-format
               '(" " mode-line-buffer-identification " "
-                (line-number-mode "%l") " " ioccur-mode-line-string "-%-"))
+                (line-number-mode "%l") " "
+                ioccur-mode-line-string "-%-"))
         (kill-local-variable 'mode-line-format)))
 
 (defsubst* ioccur-position (item seq &key (test 'eq))
@@ -154,7 +155,8 @@ Special commands:
     (lambda ()
       (let ((elm (ioccur-iter-next it)))
         (or elm
-            (progn (setq it (ioccur-iter-list lis)) (ioccur-iter-next it)))))))
+            (progn (setq it (ioccur-iter-list lis))
+                   (ioccur-iter-next it)))))))
 
 (defun ioccur-butlast (seq pos)
   "Return SEQ from index 0 to POS."
@@ -164,17 +166,20 @@ Special commands:
   "Infinite reverse iteration of SEQ starting at ELM."
   (lexical-let* ((rev-seq  (reverse seq))
                  (pos      (ioccur-position elm rev-seq :test test))
-                 (sub      (append (nthcdr (1+ pos) rev-seq) (ioccur-butlast 
rev-seq pos)))
+                 (sub      (append (nthcdr (1+ pos) rev-seq)
+                                   (ioccur-butlast rev-seq pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
        (let ((elm (ioccur-iter-next iterator)))
          (or elm
-             (progn (setq iterator (ioccur-iter-list sub)) (ioccur-iter-next 
iterator)))))))
+             (progn (setq iterator (ioccur-iter-list sub))
+                    (ioccur-iter-next iterator)))))))
 
 (defun* ioccur-sub-next-circular (seq elm &key (test 'eq))
   "Infinite iteration of SEQ starting at ELM."
   (lexical-let* ((pos      (ioccur-position elm seq :test test))
-                 (sub      (append (nthcdr (1+ pos) seq) (ioccur-butlast seq 
pos)))
+                 (sub      (append (nthcdr (1+ pos) seq)
+                                   (ioccur-butlast seq pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
        (let ((elm (ioccur-iter-next iterator)))
@@ -198,8 +203,8 @@ Special commands:
          do (incf count)
          finally return lis))))
 
-(defun* ioccur-buffer-process-ext (regex buffer &key (lline 
ioccur-length-line))
-  "Function to process buffer in external program like anything."
+(defun* ioccur-print-buffer (regex buffer &key (lline ioccur-length-line))
+  "Print matched lines in ioccur buffer."
   (setq ioccur-count-occurences 0)
   (let ((matched-lines (ioccur-find-readlines buffer regex :insert-fn 
'buffer)))
     (when matched-lines
@@ -236,7 +241,8 @@ Special commands:
   (let (pos)
     (save-excursion
       (forward-line n) (forward-line 0)
-      (when (looking-at "^ [0-9]+") (forward-line 0) (setq pos (point))))
+      (when (looking-at "^ [0-9]+")
+        (forward-line 0) (setq pos (point))))
   (when pos (goto-char pos) (ioccur-color-current-line))))
 
 ;;;###autoload
@@ -329,13 +335,15 @@ Special commands:
                          (if (< arg 0)
                              ;; M-p (move from left to right in hist ring).
                              (unless it-prec ; Don't rebuild iterator if 
exists.
-                               (setq it-prec (ioccur-sub-next-circular 
ioccur-history
-                                                                       
cur-hist-elm :test 'equal))
+                               (setq it-prec (ioccur-sub-next-circular
+                                              ioccur-history
+                                              cur-hist-elm :test 'equal))
                                (setq it-next nil)) ; Kill forward iterator.
                              ;; M-n (move from right to left in hist ring).
                              (unless it-next ; Don't rebuild iterator if 
exists.
-                               (setq it-next (ioccur-sub-prec-circular 
ioccur-history
-                                                                       
cur-hist-elm :test 'equal))
+                               (setq it-next (ioccur-sub-prec-circular
+                                              ioccur-history
+                                              cur-hist-elm :test 'equal))
                                (setq it-prec nil))) ; kill backward iterator.
                          (let ((it (or it-prec it-next)))
                            (setq cur-hist-elm (ioccur-iter-next it))
@@ -426,19 +434,21 @@ Special commands:
         (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
 
 
-(defun ioccur-filter-alist-by-regexp (regexp buffer-name)
+(defun ioccur-update-buffer (regexp buffer-name)
   "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
   (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
     (if (string= regexp "")
         (progn (erase-buffer) (insert (concat title "\n\n")))
         (erase-buffer)
-        (ioccur-buffer-process-ext regexp buffer-name :lline 
ioccur-length-line)
+        (ioccur-print-buffer regexp buffer-name :lline ioccur-length-line)
         (goto-char (point-min))
         (insert (concat title "\n\n"
-                 (propertize (format "Found %s occurences of " 
ioccur-count-occurences)
-                             'face 'underline)
-                 (propertize regexp 'face 'ioccur-regexp-face)
-                 (propertize (format " in %s" buffer-name) 'face 'underline) 
"\n\n"))
+                        (propertize (format "Found %s occurences of "
+                                            ioccur-count-occurences)
+                                    'face 'underline)
+                        (propertize regexp 'face 'ioccur-regexp-face)
+                        (propertize
+                         (format " in %s" buffer-name) 'face 'underline) 
"\n\n"))
         (ioccur-color-current-line))))
 
 
@@ -448,7 +458,7 @@ Special commands:
         (run-with-idle-timer
          ioccur-search-delay 'repeat
          #'(lambda ()
-             (ioccur-filter-alist-by-regexp
+             (ioccur-update-buffer
               ioccur-search-pattern
               ioccur-current-buffer)))))
 
@@ -531,7 +541,8 @@ for commands provided in the search buffer."
                 (push (pop (nthcdr pos-hist-elm ioccur-history))
                       ioccur-history)))
             (when (> (length ioccur-history) ioccur-max-length-history)
-              (setq ioccur-history (delete (car (last ioccur-history)) 
ioccur-history))))
+              (setq ioccur-history (delete (car (last ioccur-history))
+                                           ioccur-history))))
         (setq ioccur-count-occurences 0)
         (setq ioccur-quit-flag nil)))))
 

commit 525b3a6549b5dd77e777c189a2e6e233d837fc8d
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 9 22:28:32 2010 +0100

    Fix function names error, thank you Stepan.

diff --git a/ioccur.el b/ioccur.el
index 56895cd..ef4e1b6 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -152,9 +152,9 @@ Special commands:
   (lexical-let ((it  (ioccur-iter-list seq))
                 (lis seq))
     (lambda ()
-      (let ((elm (iter-next it)))
+      (let ((elm (ioccur-iter-next it)))
         (or elm
-            (progn (setq it (ioccur-iter-list lis)) (iter-next it)))))))
+            (progn (setq it (ioccur-iter-list lis)) (ioccur-iter-next it)))))))
 
 (defun ioccur-butlast (seq pos)
   "Return SEQ from index 0 to POS."
@@ -163,24 +163,24 @@ Special commands:
 (defun* ioccur-sub-prec-circular (seq elm &key (test 'eq))
   "Infinite reverse iteration of SEQ starting at ELM."
   (lexical-let* ((rev-seq  (reverse seq))
-                 (pos      (iter-position elm rev-seq :test test))
+                 (pos      (ioccur-position elm rev-seq :test test))
                  (sub      (append (nthcdr (1+ pos) rev-seq) (ioccur-butlast 
rev-seq pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (let ((elm (iter-next iterator)))
+       (let ((elm (ioccur-iter-next iterator)))
          (or elm
-             (progn (setq iterator (ioccur-iter-list sub)) (iter-next 
iterator)))))))
+             (progn (setq iterator (ioccur-iter-list sub)) (ioccur-iter-next 
iterator)))))))
 
 (defun* ioccur-sub-next-circular (seq elm &key (test 'eq))
   "Infinite iteration of SEQ starting at ELM."
-  (lexical-let* ((pos      (iter-position elm seq :test test))
+  (lexical-let* ((pos      (ioccur-position elm seq :test test))
                  (sub      (append (nthcdr (1+ pos) seq) (ioccur-butlast seq 
pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (let ((elm (iter-next iterator)))
+       (let ((elm (ioccur-iter-next iterator)))
          (or elm (progn
                    (setq iterator (ioccur-iter-list sub))
-                   (iter-next iterator)))))))
+                   (ioccur-iter-next iterator)))))))
 
 (defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'file))
   "Return an alist of all the (num-line line) of a file or buffer BFILE 
matching REGEXP."

commit fffb8a4b4757b057e5e964274a4b23bfc27aabd5
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 9 13:47:16 2010 +0100

    Reset start of history when using other command.

diff --git a/ioccur.el b/ioccur.el
index b6bb649..56895cd 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -361,6 +361,8 @@ Special commands:
       ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-search-pattern))))
+               (unless (or (equal char ?\M-p) (equal char ?\M-n))
+                 (setq start-hist nil) (setq cur-hist-elm (car 
ioccur-history)))
                (case char
                  ((down ?\C-n)                 ; Next line.
                   (stop-timer) (ioccur-next-line)

commit e228ee5b5a505b9965d90ba0c9ba7963ea5e7d05
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 9 12:40:15 2010 +0100

    (cycle-hist): Don't rebuild iterator when not needed.

diff --git a/ioccur.el b/ioccur.el
index 164f35f..b6bb649 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -305,7 +305,8 @@ Special commands:
   (let* ((prompt         (propertize ioccur-search-prompt 'face 
'minibuffer-prompt))
          (inhibit-quit   (not (fboundp 'read-key)))
          (tmp-list       ())
-         (it             (ioccur-iter-circular ioccur-history))
+         (it-prec        nil)
+         (it-next        nil)
          (cur-hist-elm   (car ioccur-history))
          (start-hist     nil) ; Flag to notify if cycling history started.
          (old-yank-point start-point)
@@ -327,15 +328,20 @@ Special commands:
                        (progn
                          (if (< arg 0)
                              ;; M-p (move from left to right in hist ring).
-                             (setq it (ioccur-sub-next-circular ioccur-history
-                                                                cur-hist-elm 
:test 'equal))
+                             (unless it-prec ; Don't rebuild iterator if 
exists.
+                               (setq it-prec (ioccur-sub-next-circular 
ioccur-history
+                                                                       
cur-hist-elm :test 'equal))
+                               (setq it-next nil)) ; Kill forward iterator.
                              ;; M-n (move from right to left in hist ring).
-                             (setq it (ioccur-sub-prec-circular ioccur-history
-                                                                cur-hist-elm 
:test 'equal)))
-                         (setq cur-hist-elm (ioccur-iter-next it))
-                         (setq tmp-list nil)
-                         (loop for char across cur-hist-elm do (push char 
tmp-list))
-                         (setq ioccur-search-pattern cur-hist-elm))
+                             (unless it-next ; Don't rebuild iterator if 
exists.
+                               (setq it-next (ioccur-sub-prec-circular 
ioccur-history
+                                                                       
cur-hist-elm :test 'equal))
+                               (setq it-prec nil))) ; kill backward iterator.
+                         (let ((it (or it-prec it-next)))
+                           (setq cur-hist-elm (ioccur-iter-next it))
+                           (setq tmp-list nil)
+                           (loop for char across cur-hist-elm do (push char 
tmp-list))
+                           (setq ioccur-search-pattern cur-hist-elm)))
                        ;; First call use car of history ring.
                        (setq tmp-list nil)
                        (loop for char across cur-hist-elm do (push char 
tmp-list))

commit 2e6f550913af1b72a933da66da54dde014f5c9bf
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 9 11:42:33 2010 +0100

    Simplify and fix bug in cycle-hist.

diff --git a/ioccur.el b/ioccur.el
index 843af9b..164f35f 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -318,26 +318,29 @@ Special commands:
     (flet ((cycle-hist (arg)
              (if ioccur-history
                  (progn
-                   ;; Cycle history started
+                   ;; Cycle history will start at second call,
+                   ;; at first call just use the car of hist ring.
                    ;; We build a new iterator based on a sublist
                    ;; starting at the current element of history.
                    ;; This is a circular iterator. (no end)
-                   (when start-hist
-                     (if (< arg 0) ; M-p (move from left to right in ring).
-                         (setq it (ioccur-sub-next-circular ioccur-history
-                                                            cur-hist-elm :test 
'equal))
-                         (setq it (ioccur-sub-prec-circular ioccur-history
-                                                            cur-hist-elm :test 
'equal))))
-                   (setq tmp-list nil)
-                   (let ((next (ioccur-iter-next it)))
-                     (setq next (ioccur-iter-next it))
-                     (setq start-hist nil)
-                     (setq initial-input (or next "")))
-                   (unless (string= initial-input "")
-                     (loop for char across initial-input do (push char 
tmp-list))
-                     (setq cur-hist-elm initial-input))
-                   (setq ioccur-search-pattern initial-input)
-                   (setq start-hist t))
+                   (if start-hist ; At first call start-hist is nil.
+                       (progn
+                         (if (< arg 0)
+                             ;; M-p (move from left to right in hist ring).
+                             (setq it (ioccur-sub-next-circular ioccur-history
+                                                                cur-hist-elm 
:test 'equal))
+                             ;; M-n (move from right to left in hist ring).
+                             (setq it (ioccur-sub-prec-circular ioccur-history
+                                                                cur-hist-elm 
:test 'equal)))
+                         (setq cur-hist-elm (ioccur-iter-next it))
+                         (setq tmp-list nil)
+                         (loop for char across cur-hist-elm do (push char 
tmp-list))
+                         (setq ioccur-search-pattern cur-hist-elm))
+                       ;; First call use car of history ring.
+                       (setq tmp-list nil)
+                       (loop for char across cur-hist-elm do (push char 
tmp-list))
+                       (setq ioccur-search-pattern cur-hist-elm)
+                       (setq start-hist t)))
                  (message "No history available.") (sit-for 2) t))
            ;; Maybe start timer.
            ;;

commit 4430d1e4406a08f88f87ac93c380181b8c5ed9c6
Author: Thierry Volpiatto <address@hidden>
Date:   Tue Mar 9 07:30:25 2010 +0100

    Added tag V-1.0 for changeset 026212e156b9

commit 37b6ba75e9ae2eed80c88413e1df1809a8fff699
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Mar 8 11:06:36 2010 +0100

    (ioccur-butlast): Replace subseq.

diff --git a/ioccur.el b/ioccur.el
index 7182ce9..843af9b 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -149,18 +149,22 @@ Special commands:
 
 (defun ioccur-iter-circular (seq)
   "Infinite iteration on SEQ."
-  (lexical-let ((it (ioccur-iter-list seq))
+  (lexical-let ((it  (ioccur-iter-list seq))
                 (lis seq))
     (lambda ()
       (let ((elm (iter-next it)))
         (or elm
             (progn (setq it (ioccur-iter-list lis)) (iter-next it)))))))
 
+(defun ioccur-butlast (seq pos)
+  "Return SEQ from index 0 to POS."
+  (butlast seq (- (length seq) pos)))
+
 (defun* ioccur-sub-prec-circular (seq elm &key (test 'eq))
   "Infinite reverse iteration of SEQ starting at ELM."
   (lexical-let* ((rev-seq  (reverse seq))
                  (pos      (iter-position elm rev-seq :test test))
-                 (sub      (append (nthcdr (1+ pos) rev-seq) (subseq rev-seq 0 
pos)))
+                 (sub      (append (nthcdr (1+ pos) rev-seq) (ioccur-butlast 
rev-seq pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
        (let ((elm (iter-next iterator)))
@@ -170,7 +174,7 @@ Special commands:
 (defun* ioccur-sub-next-circular (seq elm &key (test 'eq))
   "Infinite iteration of SEQ starting at ELM."
   (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (append (nthcdr (1+ pos) seq) (subseq seq 0 pos)))
+                 (sub      (append (nthcdr (1+ pos) seq) (ioccur-butlast seq 
pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
        (let ((elm (iter-next iterator)))

commit 10c90b26afa857f6d3f1e0184d2533bfc171e3ea
Author: Thierry Volpiatto <address@hidden>
Date:   Mon Mar 8 10:29:37 2010 +0100

    Introduce use of circular iterator for cycling in history.

diff --git a/ioccur.el b/ioccur.el
index 942a9b7..7182ce9 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -1,11 +1,13 @@
 ;;; ioccur.el --- Incremental occur.
 
-;; Author: Thierry Volpiatto
+;; Author: Thierry Volpiatto <thierry dot volpiatto at gmail dot com>
 
 ;; Copyright (C) 2010 Thierry Volpiatto, all rights reserved.
 
 ;; Compatibility: GNU Emacs 23.1+
 
+;; X-URL: http://mercurial.intuxication.org/hg/ioccur
+
 ;; This file is not part of GNU Emacs. 
 
 ;; This program is free software; you can redistribute it and/or
@@ -127,6 +129,11 @@ Special commands:
                 (line-number-mode "%l") " " ioccur-mode-line-string "-%-"))
         (kill-local-variable 'mode-line-format)))
 
+(defsubst* ioccur-position (item seq &key (test 'eq))
+  "A simple replacement of CL `position'."
+  (loop for i in seq for index from 0
+     when (funcall test i item) return index))
+
 ;;; Iterators.
 (defmacro ioccur-iter-list (list-obj)
   "Return an iterator from list LIST-OBJ."
@@ -140,27 +147,36 @@ Special commands:
   "Return next elm of ITERATOR."
   (funcall iterator))
 
-(defsubst* ioccur-position (item seq &key (test 'eq))
-  "A simple replacement of CL `position'."
-  (loop for i in seq for index from 0
-     when (funcall test i item) return index))
-
-(defun* ioccur-iter-sub-next (seq elm &key (test 'eq))
-  "Create iterator from position of ELM to end of SEQ."
-  (lexical-let* ((pos      (ioccur-position elm seq :test test))
-                 (sub      (nthcdr (1+ pos) seq))
+(defun ioccur-iter-circular (seq)
+  "Infinite iteration on SEQ."
+  (lexical-let ((it (ioccur-iter-list seq))
+                (lis seq))
+    (lambda ()
+      (let ((elm (iter-next it)))
+        (or elm
+            (progn (setq it (ioccur-iter-list lis)) (iter-next it)))))))
+
+(defun* ioccur-sub-prec-circular (seq elm &key (test 'eq))
+  "Infinite reverse iteration of SEQ starting at ELM."
+  (lexical-let* ((rev-seq  (reverse seq))
+                 (pos      (iter-position elm rev-seq :test test))
+                 (sub      (append (nthcdr (1+ pos) rev-seq) (subseq rev-seq 0 
pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (ioccur-iter-next iterator))))
-
-(defun* ioccur-iter-sub-prec (seq elm &key (test 'eq))
-  "Create iterator from position of ELM to beginning of SEQ."
-  (lexical-let* ((rev-seq  (reverse seq))
-                 (pos      (ioccur-position elm rev-seq :test test))
-                 (sub      (nthcdr (1+ pos) rev-seq))
+       (let ((elm (iter-next iterator)))
+         (or elm
+             (progn (setq iterator (ioccur-iter-list sub)) (iter-next 
iterator)))))))
+
+(defun* ioccur-sub-next-circular (seq elm &key (test 'eq))
+  "Infinite iteration of SEQ starting at ELM."
+  (lexical-let* ((pos      (iter-position elm seq :test test))
+                 (sub      (append (nthcdr (1+ pos) seq) (subseq seq 0 pos)))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (ioccur-iter-next iterator))))
+       (let ((elm (iter-next iterator)))
+         (or elm (progn
+                   (setq iterator (ioccur-iter-list sub))
+                   (iter-next iterator)))))))
 
 (defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'file))
   "Return an alist of all the (num-line line) of a file or buffer BFILE 
matching REGEXP."
@@ -285,7 +301,7 @@ Special commands:
   (let* ((prompt         (propertize ioccur-search-prompt 'face 
'minibuffer-prompt))
          (inhibit-quit   (not (fboundp 'read-key)))
          (tmp-list       ())
-         (it             (ioccur-iter-list ioccur-history))
+         (it             (ioccur-iter-circular ioccur-history))
          (cur-hist-elm   (car ioccur-history))
          (start-hist     nil) ; Flag to notify if cycling history started.
          (old-yank-point start-point)
@@ -294,29 +310,24 @@ Special commands:
       (loop for char across initial-input do (push char tmp-list)))
     (setq ioccur-search-pattern initial-input)
     ;; Cycle history function.
+    ;;
     (flet ((cycle-hist (arg)
              (if ioccur-history
                  (progn
                    ;; Cycle history started
                    ;; We build a new iterator based on a sublist
                    ;; starting at the current element of history.
+                   ;; This is a circular iterator. (no end)
                    (when start-hist
                      (if (< arg 0) ; M-p (move from left to right in ring).
-                         (setq it (ioccur-iter-sub-next ioccur-history
-                                                        cur-hist-elm :test 
'equal))
-                         (setq it (ioccur-iter-sub-prec ioccur-history
-                                                        cur-hist-elm :test 
'equal))))
+                         (setq it (ioccur-sub-next-circular ioccur-history
+                                                            cur-hist-elm :test 
'equal))
+                         (setq it (ioccur-sub-prec-circular ioccur-history
+                                                            cur-hist-elm :test 
'equal))))
                    (setq tmp-list nil)
                    (let ((next (ioccur-iter-next it)))
-                     ;; If no more elements in list
-                     ;; rebuild a new iterator based on the whole history list
-                     ;; and restart from beginning or end of list.
-                     (unless next
-                       (setq it (ioccur-iter-list
-                                 (if (< arg 0)
-                                     ioccur-history
-                                     (reverse ioccur-history))))
-                       (setq next (ioccur-iter-next it)) (setq start-hist nil))
+                     (setq next (ioccur-iter-next it))
+                     (setq start-hist nil)
                      (setq initial-input (or next "")))
                    (unless (string= initial-input "")
                      (loop for char across initial-input do (push char 
tmp-list))
@@ -324,11 +335,13 @@ Special commands:
                    (setq ioccur-search-pattern initial-input)
                    (setq start-hist t))
                  (message "No history available.") (sit-for 2) t))
-           
+           ;; Maybe start timer.
+           ;;
            (start-timer ()
              (unless ioccur-search-timer
                (ioccur-start-timer)))
-           
+           ;; Maybe stop timer.
+           ;;
            (stop-timer ()
              (when ioccur-search-timer
                (ioccur-cancel-search))))
@@ -362,6 +375,8 @@ Special commands:
                   (setq ioccur-exit-and-quit-p t) nil)
                  (?\C-v                        ; Scroll down.
                   (scroll-other-window 1) t)
+                 (?\M-v                        ; Scroll up.
+                  (scroll-other-window -1) t)
                  (?\C-k                        ; Kill input.
                   (start-timer)
                   (with-current-buffer ioccur-current-buffer
@@ -377,8 +392,6 @@ Special commands:
                   (unless (string= initial-input "")
                     (loop for char across initial-input do (push char 
tmp-list)))
                   (setq ioccur-search-pattern initial-input) t)
-                 (?\M-v                        ; Scroll up.
-                  (scroll-other-window -1) t)
                  (?\M-p                        ; Precedent history elm.
                   (start-timer)
                   (cycle-hist -1))

commit 03f75e32374b3490c8f6d3696c300a1af0d5d139
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 22:13:29 2010 -0800

    0.3.0

diff --git a/coffee-mode.el b/coffee-mode.el
index 8e93de5..c28b21a 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010 Chris Wanstrath
 
-;; Version 0.2.0
+;; Version 0.3.0
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
 ;; URL: http://github.com/defunkt/coffee-script
@@ -63,7 +63,7 @@
 ;; Customizable Variables
 ;;
 
-(defconst coffee-mode-version "0.2.0"
+(defconst coffee-mode-version "0.3.0"
   "The version of this `coffee-mode'.")
 
 (defgroup coffee nil

commit f7de20f4c11cb49605551fc6dc0b778803f0fd38
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 22:12:58 2010 -0800

    Just in case

diff --git a/coffee-mode.el b/coffee-mode.el
index 893a1c7..8e93de5 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -577,6 +577,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; indentation
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'coffee-indent-line)
+  (setq coffee-tab-width tab-width) ;; Just in case...
 
   ;; imenu
   (make-local-variable 'imenu-create-index-function)

commit 7976bc485545b985a89eb751923d4c4b3cdd4703
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 22:10:38 2010 -0800

    Make config options available from `customize-group`, document in README

diff --git a/README.md b/README.md
index 81379aa..91fa003 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,8 @@ Well, idiomatic CoffeeScript uses two spaces. We can set our
     (add-hook coffee-mode-hook
       '(lambda() (coffee-custom)))
 
-Another example of this hook is given further down.
+For more configuration options and another example of this hook, look
+further down in this README.
 
 ### TAB Theory
 
@@ -209,6 +210,65 @@ Naturally. Example:
 
     (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))
 
+## Configuration
+
+You can customize any of the following options using `M-x
+customize-group` with "coffee" as the group.
+
+You can also customize then with `coffee-mode-hook`, as demonstrated
+above.
+
+### coffee-debug-mode
+
+Whether to run in debug mode or not. Logs to `*Messages*`.
+
+Default: `t`
+
+### coffee-js-mode
+
+The mode to use when viewing compiled JavaScript.
+
+Default: `'js2-mode`
+
+### coffee-cleanup-whitespace
+
+Should we `delete-trailing-whitespace' on save? Probably.
+
+Default: `t`
+
+### coffee-tab-width
+
+The tab width to use when indenting.
+
+Default: `tab-width`
+
+### coffee-command
+
+The CoffeeScript command used for evaluating code. Must be in your
+path.
+
+Default: `"coffee"`
+
+### coffee-repl-args
+
+The command line arguments to pass to `coffee-command' to start a
+REPL.
+
+Default: `'("-i")`
+
+### coffee-command-args
+
+The command line arguments to pass to `coffee-command' to get it
+toprint the compiled JavaScript.
+
+Default: `'("-s" "-p" "--no-wrap")`
+
+### coffee-compiled-buffer-name
+
+The name of the scratch buffer used when compiling CoffeeScript.
+
+Default: `"*coffee-compiled*"`
+
 ## Thanks
 
 * <http://xahlee.org/emacs/elisp_syntax_coloring.html> for instructions.
diff --git a/coffee-mode.el b/coffee-mode.el
index f57d49e..893a1c7 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -66,28 +66,51 @@
 (defconst coffee-mode-version "0.2.0"
   "The version of this `coffee-mode'.")
 
-(defvar coffee-debug-mode nil
-  "Whether to run in debug mode or not. Logs to `*Messages*'.")
-
-(defvar coffee-js-mode 'js2-mode
-  "The mode to use when viewing compiled JavaScript.")
-
-(defvar coffee-cleanup-whitespace t
-  "Should we `delete-trailing-whitespace' on save? Probably.")
-
-(defvar coffee-command "coffee"
+(defgroup coffee nil
+  "A CoffeeScript major mode."
+  :group 'languages)
+
+(defcustom coffee-debug-mode nil
+  "Whether to run in debug mode or not. Logs to `*Messages*'."
+  :type 'boolean
+  :group 'coffee-mode)
+
+(defcustom coffee-js-mode 'js2-mode
+  "The mode to use when viewing compiled JavaScript."
+  :type 'string
+  :group 'coffee)
+
+(defcustom coffee-cleanup-whitespace t
+  "Should we `delete-trailing-whitespace' on save? Probably."
+  :type 'boolean
+  :group 'coffee)
+
+(defcustom coffee-tab-width tab-width
+  "The tab width to use when indenting."
+  :type 'integer
+  :group 'coffee)
+
+(defcustom coffee-command "coffee"
   "The CoffeeScript command used for evaluating code. Must be in your
-path.")
+path."
+  :type 'string
+  :group 'coffee)
 
-(defvar coffee-repl-args '("-i")
-  "The command line arguments to pass to `coffee-command' to start a REPL.")
+(defcustom coffee-repl-args '("-i")
+  "The command line arguments to pass to `coffee-command' to start a REPL."
+  :type 'list
+  :group 'coffee)
 
-(defvar coffee-command-args '("-s" "-p" "--no-wrap")
+(defcustom coffee-command-args '("-s" "-p" "--no-wrap")
   "The command line arguments to pass to `coffee-command' to get it to
-print the compiled JavaScript.")
+print the compiled JavaScript."
+  :type 'list
+  :group 'coffee)
 
-(defvar coffee-compiled-buffer-name "*coffee-compiled*"
-  "The name of the scratch buffer used when compiling CoffeeScript.")
+(defcustom coffee-compiled-buffer-name "*coffee-compiled*"
+  "The name of the scratch buffer used when compiling CoffeeScript."
+  :type 'string
+  :group 'coffee)
 
 (defvar coffee-mode-hook nil
   "A hook for you to run your own code when the mode is loaded.")
@@ -420,12 +443,12 @@ For detail, see `comment-dwim'."
         (coffee-debug "point-at-bol: %s" (point-at-bol))
 
         (when (= (point-at-bol) (point))
-          (forward-char tab-width))
+          (forward-char coffee-tab-width))
 
         (coffee-debug "New indent: %s" (current-indentation))
 
         ;; We're too far, remove all indentation.
-        (when (> (- (current-indentation) prev-indent) tab-width)
+        (when (> (- (current-indentation) prev-indent) coffee-tab-width)
           (backward-to-indentation 0)
           (delete-region (point-at-bol) (point)))))))
 
@@ -451,7 +474,7 @@ For detail, see `comment-dwim'."
   ;; level as the previous line.
   (let ((prev-indent (current-indentation)) (indent-next nil))
     (newline)
-    (insert-tab (/ prev-indent tab-width))
+    (insert-tab (/ prev-indent coffee-tab-width))
 
     ;; We need to insert an additional tab because the last line was special.
     (when (coffee-line-wants-indent)

commit adf9654673f2c57d59b8171be8535d30f3775dc7
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 21:54:00 2010 -0800

    blah

diff --git a/coffee-mode.el b/coffee-mode.el
index 13aad61..f57d49e 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -563,15 +563,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   (setq indent-tabs-mode nil)
 
   ;; hooks
-  (set (make-local-variable 'before-save-hook) 'coffee-before-save)
-
-  ;; clear memory
-  ;; TODO: make these accurate
-  (setq coffee-keywords-regexp nil)
-  (setq coffee-types-regexp nil)
-  (setq coffee-constants-regexp nil)
-  (setq coffee-events-regexp nil)
-  (setq coffee-functions-regexp nil))
+  (set (make-local-variable 'before-save-hook) 'coffee-before-save))
 
 (provide 'coffee-mode)
 

commit a9050253d9494902f21aaf6353f928f2d4662315
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 21:53:28 2010 -0800

    if the install fails...

diff --git a/README.md b/README.md
index 5d2982d..81379aa 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,11 @@ In your emacs config:
     (add-to-list 'load-path "~/.emacs.d/vendor/coffee-mode")
     (require 'coffee-mode)
 
-`coffee-mode` will be enabled automatically for any files ending in
-".coffee" or named "Cakefile".
+If `coffee-mode` is not enabled automatically for any files ending in
+".coffee" or named "Cakefile", add this to your emacs config as well:
+
+    (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
+    (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
 
 ## Indentation
 

commit d0e7c4835fa199b8f270822a22cc158d38abb9e7
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 21:34:02 2010 -0800

    the yegster

diff --git a/README.md b/README.md
index 93e022e..5d2982d 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,7 @@ Naturally. Example:
 
 * <http://xahlee.org/emacs/elisp_syntax_coloring.html> for instructions.
 * Jason Blevins for the guidance his markdown-mode.el gave.
+* Steve Yegge for js2
 
 ## Bugs
 

commit df7ae3bc3f474d15282eae829a35ed0ccad441f5
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 21:30:37 2010 -0800

    Bugfix: Indenting blank lines with TAB

diff --git a/README.md b/README.md
index 1a3e5a5..93e022e 100644
--- a/README.md
+++ b/README.md
@@ -213,8 +213,6 @@ Naturally. Example:
 
 ## Bugs
 
-Indentation on pure whitespace lines is a bit wonky.
-
 Prototype accessor assignments like `String::length: -> 10` don't look
 great.
 
diff --git a/coffee-mode.el b/coffee-mode.el
index 035e993..13aad61 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -49,7 +49,6 @@
 ;; js2-mode for guidance.
 
 ;; TODO:
-;; - Fix indentation toggling on blank (pure whitespace) lines
 ;; - Execute {buffer,region,line} and show output in new buffer
 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
 ;; - mirror-mode - close brackets and parens automatically
@@ -403,22 +402,32 @@ For detail, see `comment-dwim'."
   "Indent current line as CoffeeScript."
   (interactive)
 
-  (save-excursion
-    (let ((prev-indent 0) (cur-indent 0))
-      ;; Figure out the indentation of the previous line
-      (setd prev-indent (coffee-previous-indent))
+  (if (= (point) (point-at-bol))
+      (insert-tab)
+    (save-excursion
+      (let ((prev-indent 0) (cur-indent 0))
+        ;; Figure out the indentation of the previous line
+        (setd prev-indent (coffee-previous-indent))
 
-      ;; Figure out the current line's indentation
-      (setd cur-indent (current-indentation))
+        ;; Figure out the current line's indentation
+        (setd cur-indent (current-indentation))
 
-      ;; Shift one column to the left
-      (backward-to-indentation 0)
-      (insert-tab)
+        ;; Shift one column to the left
+        (beginning-of-line)
+        (insert-tab)
+
+        (coffee-debug "point: %s" (point))
+        (coffee-debug "point-at-bol: %s" (point-at-bol))
+
+        (when (= (point-at-bol) (point))
+          (forward-char tab-width))
+
+        (coffee-debug "New indent: %s" (current-indentation))
 
-      ;; We're too far, remove all indentation.
-      (when (> (- (current-indentation) prev-indent) tab-width)
-        (backward-to-indentation 0)
-        (delete-region (point-at-bol) (point))))))
+        ;; We're too far, remove all indentation.
+        (when (> (- (current-indentation) prev-indent) tab-width)
+          (backward-to-indentation 0)
+          (delete-region (point-at-bol) (point)))))))
 
 (defun coffee-previous-indent ()
   "Return the indentation level of the previous non-blank line."

commit b7ee8b84b7c77c9a20ff3df47b003070fd25e302
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 20:47:29 2010 -0800

    start cleaning up indentation code

diff --git a/coffee-mode.el b/coffee-mode.el
index 5ab8878..035e993 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -113,6 +113,10 @@ print the compiled JavaScript.")
   (when coffee-debug-mode
       (apply 'message (append (list string) args))))
 
+(defmacro coffee-line-as-string ()
+  "Returns the current line as a string."
+  `(buffer-substring (point-at-bol) (point-at-eol)))
+
 ;;
 ;; Commands
 ;;
@@ -399,27 +403,35 @@ For detail, see `comment-dwim'."
   "Indent current line as CoffeeScript."
   (interactive)
 
-  ;; Bail early by indenting if point as the front of the line.
-  (if (= (point) (point-at-bol))
-      (insert-tab)
-    (save-excursion
-      (let ((prev-indent 0) (cur-indent 0))
-        ;; Figure out the indentation of the previous line
-        (forward-line -1)
-        (setd prev-indent (current-indentation))
+  (save-excursion
+    (let ((prev-indent 0) (cur-indent 0))
+      ;; Figure out the indentation of the previous line
+      (setd prev-indent (coffee-previous-indent))
 
-        ;; Figure out the current line's indentation
-        (forward-line 1)
-        (setd cur-indent (current-indentation))
+      ;; Figure out the current line's indentation
+      (setd cur-indent (current-indentation))
+
+      ;; Shift one column to the left
+      (backward-to-indentation 0)
+      (insert-tab)
 
-        ;; Shift one column to the left
+      ;; We're too far, remove all indentation.
+      (when (> (- (current-indentation) prev-indent) tab-width)
         (backward-to-indentation 0)
-        (insert-tab)
+        (delete-region (point-at-bol) (point))))))
+
+(defun coffee-previous-indent ()
+  "Return the indentation level of the previous non-blank line."
+
+  (save-excursion
+    (forward-line -1)
+    (while (coffee-line-empty-p) (forward-line -1))
+    (current-indentation)))
 
-        ;; We're too far, remove all indentation.
-        (when (> (- (current-indentation) prev-indent) tab-width)
-          (backward-to-indentation 0)
-          (delete-region (point-at-bol) (point)))))))
+(defun coffee-line-empty-p ()
+  "Is this line empty? Returns non-nil if so, nil if not."
+  (or (bobp)
+   (string-match "^\\s *$" (coffee-line-as-string))))
 
 (defun coffee-newline-and-indent ()
   "Inserts a newline and indents it to the same level as the previous line."

commit a6c69113bea3cca9394c497d190f202e8341cbb6
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 20:47:19 2010 -0800

    tweaks

diff --git a/coffee-mode.el b/coffee-mode.el
index 2ab8d71..5ab8878 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -45,10 +45,12 @@
 ;; Major thanks to http://xahlee.org/emacs/elisp_syntax_coloring.html
 ;; the instructions.
 
-;; Also thanks to Jason Blevins's markdown-mode.el for guidance.
+;; Also thanks to Jason Blevins's markdown-mode.el and Steve Yegge's
+;; js2-mode for guidance.
 
 ;; TODO:
 ;; - Fix indentation toggling on blank (pure whitespace) lines
+;; - Execute {buffer,region,line} and show output in new buffer
 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
 ;; - mirror-mode - close brackets and parens automatically
 

commit 059e8898464800ef6d32cb6722d65477feed7582
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 20:06:18 2010 -0800

    typo

diff --git a/README.md b/README.md
index dcf7eb4..1a3e5a5 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,7 @@ Bind it:
 
     (define-key coffee-mode-map [(meta r)] 'coffee-compile-buffer)
 
-### coffee-compiler-region
+### coffee-compile-region
 
 Compiles the selected region to JavaScript using the same
 configuration variables as `coffee-compile-buffer`.

commit c950a25a06ea0ef40cb257ce10e0d4ecd14dac42
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 20:05:25 2010 -0800

    show menu bar

diff --git a/README.md b/README.md
index e68d468..dcf7eb4 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@ CoffeeScript Major Mode
 
 An Emacs major mode for [CoffeeScript][cs], unfancy JavaScript.
 
-Provides syntax highlighting, indentation support, imenu support, and
-a few cute commands.
+Provides syntax highlighting, indentation support, imenu support,
+a menu bar, and a few cute commands.
 
 ![Screenshot](http://img.skitch.com/20100308-fcr622c95ibey4m474d5m1m1qt.png)
 
@@ -145,6 +145,11 @@ file.
 
 ## Commands
 
+If you have `easymenu` you can get to any of these commands from the
+menu bar:
+
+![coffee-mode menu 
bar](http://img.skitch.com/20100308-tt5yn51h2jww2pmjqaawed6eq8.png)
+
 ### coffee-compile-file
 
 Compiles the current file as a JavaScript file. Doesn't open it or

commit cbd31f94b86f86eb5c799cffb8ea610e2ca75e4b
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 20:00:11 2010 -0800

    coffee-compile-file

diff --git a/README.md b/README.md
index 053c151..e68d468 100644
--- a/README.md
+++ b/README.md
@@ -145,6 +145,15 @@ file.
 
 ## Commands
 
+### coffee-compile-file
+
+Compiles the current file as a JavaScript file. Doesn't open it or
+anything special for you.
+
+Operating on "basic.coffee" and running this command will save a
+"basic.js" in the same directory. Subsequent runs will overwrite the
+file.
+
 ### coffee-compile-buffer
 
 Compiles the current buffer to JavaScript using the command specified
diff --git a/coffee-mode.el b/coffee-mode.el
index bfba3f9..2ab8d71 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -126,6 +126,15 @@ print the compiled JavaScript.")
 
   (pop-to-buffer "*CoffeeScript*"))
 
+(defun coffee-compile-file ()
+  "Compiles and saves the current file to disk. Doesn't open in a buffer.."
+  (interactive)
+  (shell-command (concat coffee-command " -c " (buffer-file-name)))
+  (message "Compiled and saved %s"
+           (concat
+            (substring (buffer-file-name) 0 -6)
+            "js")))
+
 (defun coffee-compile-buffer ()
   "Compiles the current buffer and displays the JS in another buffer."
   (interactive)
@@ -175,6 +184,7 @@ print the compiled JavaScript.")
 (easy-menu-define coffee-mode-menu coffee-mode-map
   "Menu for CoffeeScript mode"
   '("CoffeeScript"
+    ["Compile File" coffee-compile-file]
     ["Compile Buffer" coffee-compile-buffer]
     ["Compile Region" coffee-compile-region]
     ["REPL" coffee-repl]

commit 48c36c10770bf5e1e51655c67780738d9222d032
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:53:27 2010 -0800

    open node.js api in browser

diff --git a/coffee-mode.el b/coffee-mode.el
index 7928560..bfba3f9 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -158,6 +158,11 @@ print the compiled JavaScript.")
   (interactive)
   (browse-url "http://jashkenas.github.com/coffee-script/";))
 
+(defun coffee-open-node-reference ()
+  "Open browser to node.js reference."
+  (interactive)
+  (browse-url "http://nodejs.org/api.html";))
+
 (defun coffee-open-github ()
   "Open browser to `coffee-mode' project on GithHub."
   (interactive)
@@ -174,7 +179,8 @@ print the compiled JavaScript.")
     ["Compile Region" coffee-compile-region]
     ["REPL" coffee-repl]
     "---"
-    ["CoffeeScript reference" coffee-open-reference]
+    ["CoffeeScript Reference" coffee-open-reference]
+    ["node.js Reference" coffee-open-node-reference]
     ["coffee-mode on GitHub" coffee-open-github]
     ["Version" coffee-show-version]
     ))

commit 199b771328ed7fe20f0b912efc985da13e594e4d
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:45:29 2010 -0800

    0.2.0

diff --git a/coffee-mode.el b/coffee-mode.el
index ac4d7e5..7928560 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010 Chris Wanstrath
 
-;; Version 0.1.0
+;; Version 0.2.0
 ;; Keywords: CoffeeScript major mode
 ;; Author: Chris Wanstrath <address@hidden>
 ;; URL: http://github.com/defunkt/coffee-script
@@ -62,7 +62,7 @@
 ;; Customizable Variables
 ;;
 
-(defconst coffee-mode-version "0.1.0"
+(defconst coffee-mode-version "0.2.0"
   "The version of this `coffee-mode'.")
 
 (defvar coffee-debug-mode nil

commit 1b887a5d57c915d8372534d971630281cc52c501
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:42:48 2010 -0800

    clean whitespace on save

diff --git a/coffee-mode.el b/coffee-mode.el
index 8490d5e..ac4d7e5 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -50,7 +50,6 @@
 ;; TODO:
 ;; - Fix indentation toggling on blank (pure whitespace) lines
 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
-;; - Automatically `delete-trailing-whitespace' on save, configurable.
 ;; - mirror-mode - close brackets and parens automatically
 
 ;;; Code:
@@ -69,8 +68,11 @@
 (defvar coffee-debug-mode nil
   "Whether to run in debug mode or not. Logs to `*Messages*'.")
 
-(defvar coffee-mode-hook nil
-  "A hook for you to run your own code when the mode is loaded.")
+(defvar coffee-js-mode 'js2-mode
+  "The mode to use when viewing compiled JavaScript.")
+
+(defvar coffee-cleanup-whitespace t
+  "Should we `delete-trailing-whitespace' on save? Probably.")
 
 (defvar coffee-command "coffee"
   "The CoffeeScript command used for evaluating code. Must be in your
@@ -83,12 +85,12 @@ path.")
   "The command line arguments to pass to `coffee-command' to get it to
 print the compiled JavaScript.")
 
-(defvar coffee-js-mode 'js2-mode
-  "The mode to use when viewing compiled JavaScript.")
-
 (defvar coffee-compiled-buffer-name "*coffee-compiled*"
   "The name of the scratch buffer used when compiling CoffeeScript.")
 
+(defvar coffee-mode-hook nil
+  "A hook for you to run your own code when the mode is loaded.")
+
 (defvar coffee-mode-map (make-keymap)
   "Keymap for CoffeeScript major mode.")
 
@@ -241,7 +243,12 @@ print the compiled JavaScript.")
 ;; Helper Functions
 ;;
 
-;; The command to comment/uncomment text
+(defun coffee-before-save ()
+  "Hook run before file is saved. Deletes whitespace if
+`coffee-cleanup-whitespace' is non-nil."
+  (when coffee-cleanup-whitespace
+    (delete-trailing-whitespace)))
+
 (defun coffee-comment-dwim (arg)
   "Comment or uncomment current line or region in a smart way.
 For detail, see `comment-dwim'."
@@ -486,6 +493,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   "coffee-mode"
   "Major mode for editing CoffeeScript..."
 
+  ;; key bindings
   (define-key coffee-mode-map (kbd "A-r") 'coffee-compile-buffer)
   (define-key coffee-mode-map (kbd "A-R") 'coffee-compile-region)
   (define-key coffee-mode-map (kbd "A-M-r") 'coffee-repl)
@@ -515,6 +523,9 @@ line? Returns `t' or `nil'. See the README for more 
details."
   ;; no tabs
   (setq indent-tabs-mode nil)
 
+  ;; hooks
+  (set (make-local-variable 'before-save-hook) 'coffee-before-save)
+
   ;; clear memory
   ;; TODO: make these accurate
   (setq coffee-keywords-regexp nil)

commit 7f5e1b3d9c22221c08ef94e296eae0bb8adb63dc
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:37:58 2010 -0800

    Bugfix: Clear old namespace when a new one is found

diff --git a/coffee-mode.el b/coffee-mode.el
index 5bf5cde..8490d5e 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -320,7 +320,10 @@ For detail, see `comment-dwim'."
 
       ;; If this is the start of a new namespace, save the namespace's
       ;; indentation level and name.
-      (when (and (not ns-name) (setq ns-name (match-string 8)))
+      (when (match-string 8)
+        ;; Set the name.
+        (setq ns-name (match-string 8))
+
         ;; If this is a class declaration, add :: to the namespace.
         (setq ns-name (concat ns-name "::"))
 

commit 52456c0c990d817faad5165ba01a336796b1634d
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:35:44 2010 -0800

    screenshot showing off imenu

diff --git a/README.md b/README.md
index db1eafd..053c151 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ An Emacs major mode for [CoffeeScript][cs], unfancy JavaScript.
 Provides syntax highlighting, indentation support, imenu support, and
 a few cute commands.
 
-![Screenshot](http://img.skitch.com/20100307-qmcr7kij6fx7qmsx6w12dgfs2x.png)
+![Screenshot](http://img.skitch.com/20100308-fcr622c95ibey4m474d5m1m1qt.png)
 
 ## Installation
 
diff --git a/examples/basic.coffee b/examples/basic.coffee
index d183fa6..f434f81 100644
--- a/examples/basic.coffee
+++ b/examples/basic.coffee
@@ -59,11 +59,6 @@ class Horse extends Animal
 sam: new Snake "Sammy the Python"
 tom: new Horse "Tommy the Palomino"
 
-
-
-
-
-
 sam.move()
 tom.move()
 if car.speed < speed_limit then accelerate()

commit 4175d758f682ee314d08a63be5126402d9b8105b
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:33:11 2010 -0800

    Mention imenu support in README

diff --git a/README.md b/README.md
index f977640..db1eafd 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@ CoffeeScript Major Mode
 
 An Emacs major mode for [CoffeeScript][cs], unfancy JavaScript.
 
-Provides syntax highlighting, indentation support, and a few cute
-commands.
+Provides syntax highlighting, indentation support, imenu support, and
+a few cute commands.
 
 ![Screenshot](http://img.skitch.com/20100307-qmcr7kij6fx7qmsx6w12dgfs2x.png)
 
@@ -133,6 +133,16 @@ On enter would produce this:
 
 Pretty slick.
 
+## imenu
+
+If you're using imenu, `coffee-mode` should work just fine. This
+means users of [textmate.el][tm] will find that `⇧⌘T`
+(`textmate-go-to-symbol`) mostly works as expected.
+
+If you're not using imenu check out [this page][im] or textmate.el for
+a really awesome way to jump quickly to a function's definition in a
+file.
+
 ## Commands
 
 ### coffee-compile-buffer
@@ -203,3 +213,5 @@ This is the author's first major mode, so there are 
probably more
 bugs.
 
 [cs]: http://jashkenas.github.com/coffee-script/
+[tm]: http://github.com/defunkt/textmate.el
+[im]: http://chopmo.blogspot.com/2008/09/quickly-jumping-to-symbols.html
diff --git a/coffee-mode.el b/coffee-mode.el
index a18a5d9..5bf5cde 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -49,7 +49,6 @@
 
 ;; TODO:
 ;; - Fix indentation toggling on blank (pure whitespace) lines
-;; - imenu support
 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
 ;; - Automatically `delete-trailing-whitespace' on save, configurable.
 ;; - mirror-mode - close brackets and parens automatically

commit 79333bfd3979016b20bd750bf0ba31db6e843b4f
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:25:50 2010 -0800

    Bugfix: Bad binding

diff --git a/coffee-mode.el b/coffee-mode.el
index beca4ee..a18a5d9 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -485,7 +485,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
   "Major mode for editing CoffeeScript..."
 
   (define-key coffee-mode-map (kbd "A-r") 'coffee-compile-buffer)
-  (define-key coffee-mode-map (kbd "A-R") 'coffee-execute-line)
+  (define-key coffee-mode-map (kbd "A-R") 'coffee-compile-region)
   (define-key coffee-mode-map (kbd "A-M-r") 'coffee-repl)
   (define-key coffee-mode-map [remap comment-dwim] 'coffee-comment-dwim)
   (define-key coffee-mode-map "\C-m" 'coffee-newline-and-indent)

commit e1b9c837c77d58462f8861b1a67485399436fe5d
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:21:05 2010 -0800

    print full match to debug

diff --git a/coffee-mode.el b/coffee-mode.el
index 9e6d877..beca4ee 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -317,6 +317,8 @@ For detail, see `comment-dwim'."
             (point-max)
             t)
 
+      (coffee-debug "Match: %s" (match-string 0))
+
       ;; If this is the start of a new namespace, save the namespace's
       ;; indentation level and name.
       (when (and (not ns-name) (setq ns-name (match-string 8)))

commit 00c197b67fd9baa9fa112f4c8a69bdb0ececf147
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:20:56 2010 -0800

    elisp regexps are fun

diff --git a/coffee-mode.el b/coffee-mode.el
index f1bf642..9e6d877 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -189,7 +189,7 @@ print the compiled JavaScript.")
 (defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
 
 ;; Lambda
-(defvar coffee-lambda-regexp "\\((.+)\\)?\s *\\(->\\|=>\\)")
+(defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")
 
 ;; Namespaces
 (defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
@@ -319,7 +319,7 @@ For detail, see `comment-dwim'."
 
       ;; If this is the start of a new namespace, save the namespace's
       ;; indentation level and name.
-      (when (and (not ns-name) (setq ns-name (match-string 7)))
+      (when (and (not ns-name) (setq ns-name (match-string 8)))
         ;; If this is a class declaration, add :: to the namespace.
         (setq ns-name (concat ns-name "::"))
 

commit 2799609be2989d9b66651d0cb18c1f57a9c5941b
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:13:55 2010 -0800

    back out that macro change for now, something is funny

diff --git a/coffee-mode.el b/coffee-mode.el
index beaedd1..f1bf642 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -105,10 +105,10 @@ print the compiled JavaScript.")
          (setq ,var ,val))
     `(setq ,var ,val)))
 
-(defmacro coffee-debug (string &rest args)
+(defun coffee-debug (string &rest args)
   "Print a message when in debug mode."
   (when coffee-debug-mode
-    `(apply 'message (append (list ,string) ',args))))
+      (apply 'message (append (list string) args))))
 
 ;;
 ;; Commands

commit dbfaac40bee1826046a01b4aab99608581b2328e
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 19:08:06 2010 -0800

    Fix my macro

diff --git a/coffee-mode.el b/coffee-mode.el
index 4e9b8ca..beaedd1 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -108,7 +108,7 @@ print the compiled JavaScript.")
 (defmacro coffee-debug (string &rest args)
   "Print a message when in debug mode."
   (when coffee-debug-mode
-    `(apply 'message (append (list ,string) ,args))))
+    `(apply 'message (append (list ,string) ',args))))
 
 ;;
 ;; Commands

commit af021a5f0a3d0913eab56d593b14abdc267810f5
Author: Joshua Peek <address@hidden>
Date:   Sun Mar 7 17:25:34 2010 -0600

    magic autoload comments

diff --git a/coffee-mode.el b/coffee-mode.el
index 9dd35ba..4e9b8ca 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -477,6 +477,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
 ;; Define Major Mode
 ;;
 
+;;;###autoload
 (define-derived-mode coffee-mode fundamental-mode
   "coffee-mode"
   "Major mode for editing CoffeeScript..."
@@ -525,5 +526,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
 ;;
 
 ;; Run coffee-mode for files ending in .coffee.
+;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
+;;;###autoload
 (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))

commit c6562afd3370ab4972771286e71a27557befc9d1
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 18:49:33 2010 -0800

    Make `coffee-debug' a macro

diff --git a/coffee-mode.el b/coffee-mode.el
index b8dc9ca..9dd35ba 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -100,10 +100,15 @@ print the compiled JavaScript.")
 (defmacro setd (var val)
   "Like setq but optionally logs the variable's value using `coffee-debug'."
   (if coffee-debug-mode
-  `(progn
-     (coffee-debug "%s: %s" ',var ,val)
-     (setq ,var ,val))
-  `(setq ,var ,val)))
+      `(progn
+         (coffee-debug "%s: %s" ',var ,val)
+         (setq ,var ,val))
+    `(setq ,var ,val)))
+
+(defmacro coffee-debug (string &rest args)
+  "Print a message when in debug mode."
+  (when coffee-debug-mode
+    `(apply 'message (append (list ,string) ,args))))
 
 ;;
 ;; Commands
@@ -250,11 +255,6 @@ For detail, see `comment-dwim'."
   "The full `coffee-command' complete with args."
   (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
 
-(defun coffee-debug (string &rest args)
-  "Print a message when in debug mode."
-  (when coffee-debug-mode
-      (apply 'message (append (list string) args))))
-
 ;;
 ;; imenu support
 ;;
@@ -304,7 +304,7 @@ For detail, see `comment-dwim'."
 
   (let ((index-alist '()) assign pos indent ns-name ns-indent)
     ;; Go through every assignment that includes -> or => on the same
-    ;; line.
+    ;; line or starts with `class'.
     (while (re-search-forward
             (concat "^\\(\\s *\\)"
                     "\\("

commit 76ed341718f0694bb58f0027f207eff51dae478f
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 18:44:18 2010 -0800

    class support in imenu

diff --git a/coffee-mode.el b/coffee-mode.el
index 63059ce..b8dc9ca 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -186,6 +186,9 @@ print the compiled JavaScript.")
 ;; Lambda
 (defvar coffee-lambda-regexp "\\((.+)\\)?\s *\\(->\\|=>\\)")
 
+;; Namespaces
+(defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
+
 ;; Booleans
 (defvar coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\)\\b")
 
@@ -267,8 +270,6 @@ For detail, see `comment-dwim'."
 ;; block: ->
 ;;   print('potion')
 ;;
-;; (TODO: This next part is incomplete and therefor a lie.)
-;;
 ;; Next we look for any line that starts with `class' or
 ;; `coffee-assign-regexp' followed by `{` and drop into a
 ;; namespace. This means we search one indentation level deeper for
@@ -287,6 +288,7 @@ For detail, see `comment-dwim'."
 ;;   print: ->
 ;;     print 'My name is ' + this.name + " and I'm a " + this.rank + '.'
 ;;
+;; TODO:
 ;; app = {
 ;;   window:  {width: 200, height: 200}
 ;;   para:    -> 'Welcome.'
@@ -300,26 +302,60 @@ For detail, see `comment-dwim'."
   ;; This function is called within a `save-excursion' so we're safe.
   (beginning-of-buffer)
 
-  (let ((index-alist '()) assign pos func)
+  (let ((index-alist '()) assign pos indent ns-name ns-indent)
     ;; Go through every assignment that includes -> or => on the same
     ;; line.
     (while (re-search-forward
-            (concat "^\\s *"
-                    coffee-assign-regexp
-                    ".+?"
-                    coffee-lambda-regexp)
+            (concat "^\\(\\s *\\)"
+                    "\\("
+                      coffee-assign-regexp
+                      ".+?"
+                      coffee-lambda-regexp
+                    "\\|"
+                      coffee-namespace-regexp
+                    "\\)")
             (point-max)
             t)
 
-      ;; The token being assigned. `Please.print:` will be
-      ;; `Please.print`, `block:` will be `block`, etc.
-      (setd assign (match-string 1))
-
-      ;; The position of the match in the buffer.
-      (setd pos (match-beginning 0))
-
-      ;; Add this to the alist. Done.
-      (push (cons assign pos) index-alist))
+      ;; If this is the start of a new namespace, save the namespace's
+      ;; indentation level and name.
+      (when (and (not ns-name) (setq ns-name (match-string 7)))
+        ;; If this is a class declaration, add :: to the namespace.
+        (setq ns-name (concat ns-name "::"))
+
+        ;; Save the indentation level.
+        (setq ns-indent (length (match-string 1)))
+
+        ;; Debug
+        (coffee-debug "ns: Found %s with indent %s" ns-name ns-indent))
+
+      ;; If this is an assignment, save the token being
+      ;; assigned. `Please.print:` will be `Please.print`, `block:`
+      ;; will be `block`, etc.
+      (when (setq assign (match-string 3))
+          ;; The position of the match in the buffer.
+          (setq pos (match-beginning 3))
+
+          ;; The indent level of this match
+          (setq indent (length (match-string 1)))
+
+          ;; If we're within the context of a namespace, add that to the
+          ;; front of the assign, e.g.
+          ;; constructor: => Policeman::constructor
+          (when (and ns-name (> indent ns-indent))
+            (setq assign (concat ns-name assign)))
+
+          (coffee-debug "=: Found %s with indent %s" assign indent)
+
+          ;; Clear the namespace if we're no longer indented deeper
+          ;; than it.
+          (when (and ns-name (<= indent ns-indent))
+            (coffee-debug "ns: Clearing %s" ns-name)
+            (setq ns-name nil)
+            (setq ns-indent nil))
+
+          ;; Add this to the alist. Done.
+          (push (cons assign pos) index-alist)))
 
     ;; Return the alist.
     index-alist))

commit 169e66dd3e28a9d2ca70fece895bf31ff940d89f
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 17:23:47 2010 -0800

    lies

diff --git a/coffee-mode.el b/coffee-mode.el
index a555b77..63059ce 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -267,6 +267,8 @@ For detail, see `comment-dwim'."
 ;; block: ->
 ;;   print('potion')
 ;;
+;; (TODO: This next part is incomplete and therefor a lie.)
+;;
 ;; Next we look for any line that starts with `class' or
 ;; `coffee-assign-regexp' followed by `{` and drop into a
 ;; namespace. This means we search one indentation level deeper for

commit 21ce2dada02016a9cf795c8325985d2dfe099a00
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 17:22:12 2010 -0800

    The kind of optimization that turns on every Lisp hacker: macro-time.

diff --git a/coffee-mode.el b/coffee-mode.el
index b81cef9..a555b77 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -99,9 +99,11 @@ print the compiled JavaScript.")
 
 (defmacro setd (var val)
   "Like setq but optionally logs the variable's value using `coffee-debug'."
+  (if coffee-debug-mode
   `(progn
      (coffee-debug "%s: %s" ',var ,val)
-     (setq ,var ,val)))
+     (setq ,var ,val))
+  `(setq ,var ,val)))
 
 ;;
 ;; Commands

commit 590873fbec21bdeabf42b35691eb54bff4898a25
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 17:20:04 2010 -0800

    Add imenu.coffee example

diff --git a/examples/imenu.coffee b/examples/imenu.coffee
new file mode 100644
index 0000000..fc17c5d
--- /dev/null
+++ b/examples/imenu.coffee
@@ -0,0 +1,34 @@
+# Testing imenu
+regexp: /asdas/
+two: 4 / 2
+
+minus: (x, y) -> x - y
+
+String::length: -> 10
+
+class Person
+  print: ->
+    print 'My name is ' + this.name + '.'
+
+app = {
+  window:  {width: 200, height: 200}
+  para:    'Welcome.'
+  button:  'OK'
+}
+
+block: ->
+  print('potion')
+
+Please: {}
+Please.print: (word) ->
+  print(word)
+
+HomePage::get: (url) ->
+  session: url.query.session if url.query?
+
+class Policeman extends Person
+  constructor: (rank) ->
+    @rank: rank
+
+  print: ->
+    print 'My name is ' + this.name + " and I'm a " + this.rank + '.'

commit 30d2af5a1ea7eab62c0dd4a3fa40e5a371990e5d
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 17:19:58 2010 -0800

    Basic imenu support - makes things like `textmate-goto-symbol' work!

diff --git a/coffee-mode.el b/coffee-mode.el
index 20efc30..b81cef9 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -179,7 +179,10 @@ print the compiled JavaScript.")
 (defvar coffee-this-regexp "@\\w*\\|this")
 
 ;; Assignment
-(defvar coffee-assign-regexp "\\(\\w\\|\\.\\|_\\| \\|$\\)+?:")
+(defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
+
+;; Lambda
+(defvar coffee-lambda-regexp "\\((.+)\\)?\s *\\(->\\|=>\\)")
 
 ;; Booleans
 (defvar coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\)\\b")
@@ -248,6 +251,76 @@ For detail, see `comment-dwim'."
       (apply 'message (append (list string) args))))
 
 ;;
+;; imenu support
+;;
+
+;; This is a pretty naive but workable way of doing it. First we look
+;; for any lines that starting with `coffee-assign-regexp' that include
+;; `coffee-lambda-regexp' then add those tokens to the list.
+;;
+;; Should cover cases like these:
+;;
+;; minus: (x, y) -> x - y
+;; String::length: -> 10
+;; block: ->
+;;   print('potion')
+;;
+;; Next we look for any line that starts with `class' or
+;; `coffee-assign-regexp' followed by `{` and drop into a
+;; namespace. This means we search one indentation level deeper for
+;; more assignments and add them to the alist prefixed with the
+;; namespace name.
+;;
+;; Should cover cases like these:
+;;
+;; class Person
+;;   print: ->
+;;     print 'My name is ' + this.name + '.'
+;;
+;; class Policeman extends Person
+;;   constructor: (rank) ->
+;;     @rank: rank
+;;   print: ->
+;;     print 'My name is ' + this.name + " and I'm a " + this.rank + '.'
+;;
+;; app = {
+;;   window:  {width: 200, height: 200}
+;;   para:    -> 'Welcome.'
+;;   button:  -> 'OK'
+;; }
+
+(defun coffee-imenu-create-index ()
+  "Create an imenu index of all methods in the buffer."
+  (interactive)
+
+  ;; This function is called within a `save-excursion' so we're safe.
+  (beginning-of-buffer)
+
+  (let ((index-alist '()) assign pos func)
+    ;; Go through every assignment that includes -> or => on the same
+    ;; line.
+    (while (re-search-forward
+            (concat "^\\s *"
+                    coffee-assign-regexp
+                    ".+?"
+                    coffee-lambda-regexp)
+            (point-max)
+            t)
+
+      ;; The token being assigned. `Please.print:` will be
+      ;; `Please.print`, `block:` will be `block`, etc.
+      (setd assign (match-string 1))
+
+      ;; The position of the match in the buffer.
+      (setd pos (match-beginning 0))
+
+      ;; Add this to the alist. Done.
+      (push (cons assign pos) index-alist))
+
+    ;; Return the alist.
+    index-alist))
+
+;;
 ;; Indentation
 ;;
 
@@ -390,10 +463,15 @@ line? Returns `t' or `nil'. See the README for more 
details."
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'coffee-indent-line)
 
+  ;; imenu
+  (make-local-variable 'imenu-create-index-function)
+  (setq imenu-create-index-function 'coffee-imenu-create-index)
+
   ;; no tabs
   (setq indent-tabs-mode nil)
 
   ;; clear memory
+  ;; TODO: make these accurate
   (setq coffee-keywords-regexp nil)
   (setq coffee-types-regexp nil)
   (setq coffee-constants-regexp nil)

commit c5ffe040b9533fa0e4d94b68e0371f29ca9c75ed
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 16:05:41 2010 -0800

    setd macro for logging variable values when setting them

diff --git a/coffee-mode.el b/coffee-mode.el
index 6295ff0..20efc30 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -94,9 +94,15 @@ print the compiled JavaScript.")
   "Keymap for CoffeeScript major mode.")
 
 ;;
-;; Private Variables
+;; Macros
 ;;
 
+(defmacro setd (var val)
+  "Like setq but optionally logs the variable's value using `coffee-debug'."
+  `(progn
+     (coffee-debug "%s: %s" ',var ,val)
+     (setq ,var ,val)))
+
 ;;
 ;; Commands
 ;;
@@ -236,10 +242,10 @@ For detail, see `comment-dwim'."
   "The full `coffee-command' complete with args."
   (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
 
-(defun coffee-debug (string &optional args)
+(defun coffee-debug (string &rest args)
   "Print a message when in debug mode."
   (when coffee-debug-mode
-      (message string args)))
+      (apply 'message (append (list string) args))))
 
 ;;
 ;; Indentation
@@ -258,17 +264,14 @@ For detail, see `comment-dwim'."
       (let ((prev-indent 0) (cur-indent 0))
         ;; Figure out the indentation of the previous line
         (forward-line -1)
-        (setq prev-indent (current-indentation))
-        (coffee-debug "prev-indent %s" prev-indent)
+        (setd prev-indent (current-indentation))
 
         ;; Figure out the current line's indentation
         (forward-line 1)
-        (setq cur-indent (current-indentation))
-        (coffee-debug "cur-indent %s" cur-indent)
+        (setd cur-indent (current-indentation))
 
         ;; Shift one column to the left
         (backward-to-indentation 0)
-        (coffee-debug "backward cur-indent %s" (current-indentation))
         (insert-tab)
 
         ;; We're too far, remove all indentation.
@@ -328,7 +331,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
       ;; If the next few characters match one of our magic indenter
       ;; keywords, we want to indent the line we were on originally.
       (when (looking-at (coffee-indenters-bol-regexp))
-        (setq indenter-at-bol t))
+        (setd indenter-at-bol t))
 
       ;; If that didn't match, go to the back of the line and check to
       ;; see if the last character matches one of our indenter
@@ -340,7 +343,7 @@ line? Returns `t' or `nil'. See the README for more 
details."
         (when (some (lambda (char)
                         (= (char-before) char))
                       coffee-indenters-eol)
-          (setq indenter-at-eol t)))
+          (setd indenter-at-eol t)))
 
       ;; If we found an indenter, return `t'.
       (or indenter-at-bol indenter-at-eol))))

commit 5b00ae2e64bb74ff92abd9c510b205747fbe43f9
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 15:43:09 2010 -0800

    more todo

diff --git a/coffee-mode.el b/coffee-mode.el
index 8cffe6a..6295ff0 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -51,6 +51,8 @@
 ;; - Fix indentation toggling on blank (pure whitespace) lines
 ;; - imenu support
 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
+;; - Automatically `delete-trailing-whitespace' on save, configurable.
+;; - mirror-mode - close brackets and parens automatically
 
 ;;; Code:
 
@@ -82,10 +84,6 @@ path.")
   "The command line arguments to pass to `coffee-command' to get it to
 print the compiled JavaScript.")
 
-(defun coffee-command-full ()
-  "The full `coffee-command' complete with args."
-  (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
-
 (defvar coffee-js-mode 'js2-mode
   "The mode to use when viewing compiled JavaScript.")
 
@@ -96,6 +94,10 @@ print the compiled JavaScript.")
   "Keymap for CoffeeScript major mode.")
 
 ;;
+;; Private Variables
+;;
+
+;;
 ;; Commands
 ;;
 
@@ -230,6 +232,10 @@ For detail, see `comment-dwim'."
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
+(defun coffee-command-full ()
+  "The full `coffee-command' complete with args."
+  (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
+
 (defun coffee-debug (string &optional args)
   "Print a message when in debug mode."
   (when coffee-debug-mode

commit 12bd5d09058ad9613a70b14f17e14fd8f0446123
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 15:19:46 2010 -0800

    todo

diff --git a/coffee-mode.el b/coffee-mode.el
index daa2393..8cffe6a 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -47,6 +47,13 @@
 
 ;; Also thanks to Jason Blevins's markdown-mode.el for guidance.
 
+;; TODO:
+;; - Fix indentation toggling on blank (pure whitespace) lines
+;; - imenu support
+;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
+
+;;; Code:
+
 (require 'easymenu)
 (require 'font-lock)
 (require 'cl)

commit c492a2056793a8861c115f895f7cfa48e75a89c9
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 14:55:20 2010 -0800

    doc tweaks

diff --git a/README.md b/README.md
index bbd22e9..f977640 100644
--- a/README.md
+++ b/README.md
@@ -46,9 +46,10 @@ Another example of this hook is given further down.
 
 ### TAB Theory
 
-When you press `TAB`, indent the line unless doing so would make the
-current line more than two indentation levels deepers than the
-previous line. If that's the case, remove all indentation.
+It goes like this: when you press `TAB`, we indent the line unless
+doing so would make the current line more than two indentation levels
+deepers than the previous line. If that's the case, remove all
+indentation.
 
 Consider this code, with point at the position indicated by the
 caret:
@@ -73,12 +74,12 @@ Pressing `TAB` again will produce this code:
        ^
 
 And so on. I think this is a pretty good way of getting decent
-indentation with a whitespace-sensitive
+indentation with a whitespace-sensitive language.
 
 ### Newline and Indent
 
-As for indentation after newlines, given this code and cursor
-position:
+We all love hitting `RET` and having the next line indented
+properly. Given this code and cursor position:
 
     line1()
       line2()
@@ -101,7 +102,7 @@ able to get things where you want them pretty easily.
 ### Indenters
 
 `class`, `for`, `if`, and possibly other keywords cause the next line
-to be indented automatically, however.
+to be indented a level deeper automatically.
 
 For example, given this code and cursor position::
 

commit e2ead2595aff7c38544cbfca9bb06afbcb0ffd3f
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 23:33:05 2010 +0100

    Clean ioccur-read-search-input.

diff --git a/ioccur.el b/ioccur.el
index 4a38d18..942a9b7 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -293,6 +293,7 @@ Special commands:
     (unless (string= initial-input "")
       (loop for char across initial-input do (push char tmp-list)))
     (setq ioccur-search-pattern initial-input)
+    ;; Cycle history function.
     (flet ((cycle-hist (arg)
              (if ioccur-history
                  (progn
@@ -311,9 +312,10 @@ Special commands:
                      ;; rebuild a new iterator based on the whole history list
                      ;; and restart from beginning or end of list.
                      (unless next
-                       (setq it (ioccur-iter-list (if (< arg 0)
-                                               ioccur-history
-                                               (reverse ioccur-history))))
+                       (setq it (ioccur-iter-list
+                                 (if (< arg 0)
+                                     ioccur-history
+                                     (reverse ioccur-history))))
                        (setq next (ioccur-iter-next it)) (setq start-hist nil))
                      (setq initial-input (or next "")))
                    (unless (string= initial-input "")
@@ -321,32 +323,33 @@ Special commands:
                      (setq cur-hist-elm initial-input))
                    (setq ioccur-search-pattern initial-input)
                    (setq start-hist t))
-                 (message "No history available.") (sit-for 2) t)))
+                 (message "No history available.") (sit-for 2) t))
+           
+           (start-timer ()
+             (unless ioccur-search-timer
+               (ioccur-start-timer)))
+           
+           (stop-timer ()
+             (when ioccur-search-timer
+               (ioccur-cancel-search))))
+      ;; Start incremental loop.
       (while (let ((char (ioccur-read-char-or-event
                           (concat prompt ioccur-search-pattern))))
                (case char
                  ((down ?\C-n)                 ; Next line.
-                  (when ioccur-search-timer
-                    (ioccur-cancel-search))
-                  (ioccur-next-line)
+                  (stop-timer) (ioccur-next-line)
                   (ioccur-color-current-line) t)
                  ((up ?\C-p)                   ; Precedent line.
-                  (when ioccur-search-timer
-                    (ioccur-cancel-search))
-                  (ioccur-precedent-line)
+                  (stop-timer) (ioccur-precedent-line)
                   (ioccur-color-current-line) t)
                  (C-down                       ; Scroll both windows down.
-                  (when ioccur-search-timer
-                    (ioccur-cancel-search))
+                  (stop-timer)
                   (ioccur-scroll-down) t)
                  (C-up                         ; Scroll both windows up.
-                  (when ioccur-search-timer
-                    (ioccur-cancel-search))
-                  (ioccur-scroll-up) t)
+                  (stop-timer) (ioccur-scroll-up) t)
                  ((?\e ?\r) (message nil) nil) ; RET or ESC break and exit 
code.
                  (?\d                          ; Delete backward with DEL.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
@@ -360,20 +363,16 @@ Special commands:
                  (?\C-v                        ; Scroll down.
                   (scroll-other-window 1) t)
                  (?\C-k                        ; Kill input.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (goto-char old-yank-point)
                     (setq yank-point old-yank-point))
-                  (kill-new ioccur-search-pattern)
-                  (setq tmp-list ()) t)
+                  (kill-new ioccur-search-pattern) (setq tmp-list ()) t)
                  (?\C-w                        ; Yank stuff at point.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (with-current-buffer ioccur-current-buffer
                     (unless old-yank-point (setq old-yank-point (point)))
-                    (setq yank-point (point))
-                    (forward-word 1)
+                    (setq yank-point (point)) (forward-word 1)
                     (setq initial-input (buffer-substring yank-point (point))))
                   (unless (string= initial-input "")
                     (loop for char across initial-input do (push char 
tmp-list)))
@@ -381,16 +380,13 @@ Special commands:
                  (?\M-v                        ; Scroll up.
                   (scroll-other-window -1) t)
                  (?\M-p                        ; Precedent history elm.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (cycle-hist -1))
                  (?\M-n                        ; Next history elm.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (cycle-hist 1))
                  (t                            ; Store character.
-                  (unless ioccur-search-timer
-                    (ioccur-start-timer))
+                  (start-timer)
                   (if (characterp char)
                       (push char tmp-list)
                       ;; Else, a non--character event is entered, not listed 
above.

commit 1caa0dcdf6353763d7ba4cc585baae980fa30852
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 19:07:57 2010 +0100

    (ioccur-color-current-line, ioccur-color-matched-line): Simplify.

diff --git a/ioccur.el b/ioccur.el
index 738c5d8..4a38d18 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -521,25 +521,21 @@ for commands provided in the search buffer."
 
 (defun ioccur-color-current-line ()
   "Highlight and underline current line in ioccur buffer."
-  (if (not ioccur-occur-overlay)
-      (setq ioccur-occur-overlay
-            (make-overlay
-             (line-beginning-position) (1+ (line-end-position))))
+  (if ioccur-occur-overlay
       (move-overlay ioccur-occur-overlay
-                    (line-beginning-position) (1+ (line-end-position))))
-  (overlay-put ioccur-occur-overlay
-               'face 'ioccur-overlay-face))
+                    (point-at-bol) (1+ (point-at-eol)))
+      (setq ioccur-occur-overlay
+            (make-overlay (point-at-bol) (1+ (point-at-eol)))))
+  (overlay-put ioccur-occur-overlay 'face 'ioccur-overlay-face))
 
 (defun ioccur-color-matched-line ()
   "Highlight and underline current position on matched line in current-buffer."
-  (if (not ioccur-match-overlay)
-      (setq ioccur-match-overlay
-            (make-overlay
-             (line-beginning-position) (1+ (line-end-position))))
+  (if ioccur-match-overlay
       (move-overlay ioccur-match-overlay
-                    (line-beginning-position) (1+ (line-end-position))))
-  (overlay-put ioccur-match-overlay
-               'face 'ioccur-match-overlay-face))
+                    (point-at-bol) (1+ (point-at-eol)))
+      (setq ioccur-match-overlay
+            (make-overlay (point-at-bol) (1+ (point-at-eol)))))
+  (overlay-put ioccur-match-overlay 'face 'ioccur-match-overlay-face))
 
 ;;; Provide
 (provide 'ioccur)

commit fb2a2d0155a495e61f009b3949cee23fadecaf04
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 15:14:46 2010 +0100

    No code change, only comments and docstring.

diff --git a/ioccur.el b/ioccur.el
index 2a03525..738c5d8 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -23,6 +23,14 @@
 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 ;; Floor, Boston, MA 02110-1301, USA.
 
+;;; Install:
+;;  -------
+
+;; Add this file to your `load-path', BYTE-COMPILE it and
+;; add (require 'ioccur) in your .emacs.
+;; Start with M-x ioccur
+
+
 ;;; Code:
 (require 'derived)
 (eval-when-compile (require 'cl))
@@ -59,9 +67,8 @@
 
 (defcustom ioccur-mode-line-string
   " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Scroll, C-w:Yank tap"
-  "*Documentation of `ioccur-occur' prompt displayed in mode-line.
-Set it to nil to remove doc in mode-line.
-If you use this you will want maybe to set `ioccur-docstring' to nil"
+  "*Documentation of `ioccur' prompt displayed in mode-line.
+Set it to nil to remove doc in mode-line."
   :group 'ioccur
   :type  'string)
 
@@ -524,7 +531,7 @@ for commands provided in the search buffer."
                'face 'ioccur-overlay-face))
 
 (defun ioccur-color-matched-line ()
-  "Highlight and current position on matched line."
+  "Highlight and underline current position on matched line in current-buffer."
   (if (not ioccur-match-overlay)
       (setq ioccur-match-overlay
             (make-overlay

commit c063681486d8318870382ae6575ff2e2b8c1025a
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 04:13:12 2010 -0800

    no more debug mode

diff --git a/coffee-mode.el b/coffee-mode.el
index 68cf729..daa2393 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -58,7 +58,7 @@
 (defconst coffee-mode-version "0.1.0"
   "The version of this `coffee-mode'.")
 
-(defvar coffee-debug-mode t
+(defvar coffee-debug-mode nil
   "Whether to run in debug mode or not. Logs to `*Messages*'.")
 
 (defvar coffee-mode-hook nil

commit dc7d65764d98d6e5bbf5f8e807483dda09848084
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 04:01:17 2010 -0800

    also that

diff --git a/README.md b/README.md
index 82fd247..bbd22e9 100644
--- a/README.md
+++ b/README.md
@@ -190,6 +190,9 @@ Naturally. Example:
 
 Indentation on pure whitespace lines is a bit wonky.
 
+Prototype accessor assignments like `String::length: -> 10` don't look
+great.
+
 It's tested on Aquamacs 1.9 (Emacs 22) for OS X Snow Leopard so it may
 not work on your environment. Please file a bug at
 <http://github.com/defunkt/coffee-mode/issues> and maybe we can fix

commit bab59d563851290b5e2bb12208479854f8f75c9e
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:56:20 2010 -0800

    wonky

diff --git a/README.md b/README.md
index cbfc973..82fd247 100644
--- a/README.md
+++ b/README.md
@@ -188,12 +188,14 @@ Naturally. Example:
 
 ## Bugs
 
+Indentation on pure whitespace lines is a bit wonky.
+
 It's tested on Aquamacs 1.9 (Emacs 22) for OS X Snow Leopard so it may
 not work on your environment. Please file a bug at
 <http://github.com/defunkt/coffee-mode/issues> and maybe we can fix
 the problem.
 
-This is the author's first major mode. Any sort of style feedback is
-appreciated.
+This is the author's first major mode, so there are probably more
+bugs.
 
 [cs]: http://jashkenas.github.com/coffee-script/

commit c93d795692bc71abe8eff60ec8823a10a4e4a4a7
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:42:48 2010 -0800

    fix config example

diff --git a/README.md b/README.md
index f7a790d..cbfc973 100644
--- a/README.md
+++ b/README.md
@@ -166,12 +166,20 @@ Naturally. Example:
 
     (defun coffee-custom ()
       "coffee-mode-hook"
+
+      ;; CoffeeScript uses two spaces.
       (set (make-local-variable 'tab-width) 2)
+
+      ;; If you don't have js2-mode
+      (setq coffee-js-mode 'javascript-mode)
+
+      ;; *Messages* spam
       (setq coffee-debug-mode t)
-      (setq coffee-command "~/dev/coffee))
 
-    (add-hook coffee-mode-hook
-      '(lambda() (coffee-custom)))
+      ;; Riding edge.
+      (setq coffee-command "~/dev/coffee"))
+
+    (add-hook 'coffee-mode-hook '(lambda () (coffee-custom)))
 
 ## Thanks
 

commit ff6170061e52dd85864d2e9e490afcce0fe390c5
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:37:35 2010 -0800

    that was bothering me

diff --git a/coffee-mode.el b/coffee-mode.el
index 1eb3e07..68cf729 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -198,20 +198,17 @@ print the compiled JavaScript.")
                                  coffee-cs-keywords) 'words))
 
 
-;; Create the list for font-lock.
-;; Each class of keyword is given a particular face
+;; Create the list for font-lock. Each class of keyword is given a
+;; particular face.
 (defvar coffee-font-lock-keywords
-      `(
-        (,coffee-this-regexp . font-lock-variable-name-face)
-        (,coffee-assign-regexp . font-lock-type-face)
-        (,coffee-regexp-regexp . font-lock-constant-face)
-        (,coffee-boolean-regexp . font-lock-constant-face)
-        (,coffee-keywords-regexp . font-lock-keyword-face)
-
-        ;; note: order above matters. `coffee-keywords-regexp' goes last 
because
-        ;; otherwise the keyword "state" in the function "state_entry"
-        ;; would be highlighted.
-        ))
+  ;; *Note*: order below matters. `coffee-keywords-regexp' goes last
+  ;; because otherwise the keyword "state" in the function
+  ;; "state_entry" would be highlighted.
+  `((,coffee-this-regexp . font-lock-variable-name-face)
+    (,coffee-assign-regexp . font-lock-type-face)
+    (,coffee-regexp-regexp . font-lock-constant-face)
+    (,coffee-boolean-regexp . font-lock-constant-face)
+    (,coffee-keywords-regexp . font-lock-keyword-face)))
 
 ;;
 ;; Helper Functions

commit 54945957d0ee696cec125b258c592544a361aa5d
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:35:23 2010 -0800

    first major mode

diff --git a/README.md b/README.md
index 0e4a31f..f7a790d 100644
--- a/README.md
+++ b/README.md
@@ -185,4 +185,7 @@ not work on your environment. Please file a bug at
 <http://github.com/defunkt/coffee-mode/issues> and maybe we can fix
 the problem.
 
+This is the author's first major mode. Any sort of style feedback is
+appreciated.
+
 [cs]: http://jashkenas.github.com/coffee-script/

commit 4ab14673e3cefc7208cb18a2beeec6f92f2b9a8e
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:32:08 2010 -0800

    no more test.coffee

diff --git a/test.coffee b/test.coffee
deleted file mode 100644
index c74e1af..0000000
--- a/test.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-Person: {
-  hi: "world"
-
-  world: "hi"
-}
-
-hi: "mom"
-
-Person: {
-
-
-
-class Dog
-  constructor: (hey) =>
-
-
-
-
-
-
-
-
-
-
-
-

commit 97ef92b61c61df487ac194ec95b9b2f1fa8b09f8
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:31:56 2010 -0800

    Bugfix: Indentation works when point is at beginning of the line

diff --git a/coffee-mode.el b/coffee-mode.el
index b96e01a..1eb3e07 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -241,27 +241,30 @@ For detail, see `comment-dwim'."
   "Indent current line as CoffeeScript."
   (interactive)
 
-  (save-excursion
-    (let ((prev-indent 0) (cur-indent 0))
-      ;; Figure out the indentation of the previous line
-      (forward-line -1)
-      (setq prev-indent (current-indentation))
-      (coffee-debug "prev-indent %s" prev-indent)
-
-      ;; Figure out the current line's indentation
-      (forward-line 1)
-      (setq cur-indent (current-indentation))
-      (coffee-debug "cur-indent %s" cur-indent)
-
-      ;; Shift one column to the left
-      (backward-to-indentation 0)
-      (coffee-debug "backward cur-indent %s" (current-indentation))
+  ;; Bail early by indenting if point as the front of the line.
+  (if (= (point) (point-at-bol))
       (insert-tab)
-
-      ;; We're too far, remove all indentation.
-      (when (> (- (current-indentation) prev-indent) tab-width)
+    (save-excursion
+      (let ((prev-indent 0) (cur-indent 0))
+        ;; Figure out the indentation of the previous line
+        (forward-line -1)
+        (setq prev-indent (current-indentation))
+        (coffee-debug "prev-indent %s" prev-indent)
+
+        ;; Figure out the current line's indentation
+        (forward-line 1)
+        (setq cur-indent (current-indentation))
+        (coffee-debug "cur-indent %s" cur-indent)
+
+        ;; Shift one column to the left
         (backward-to-indentation 0)
-        (delete-region (point-at-bol) (point))))))
+        (coffee-debug "backward cur-indent %s" (current-indentation))
+        (insert-tab)
+
+        ;; We're too far, remove all indentation.
+        (when (> (- (current-indentation) prev-indent) tab-width)
+          (backward-to-indentation 0)
+          (delete-region (point-at-bol) (point)))))))
 
 (defun coffee-newline-and-indent ()
   "Inserts a newline and indents it to the same level as the previous line."

commit 60dcfd6dcc195c4b0887eb75acc5b71571c0da1c
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 12:31:33 2010 +0100

    Rename ioccur-iter-position to ioccur-position

diff --git a/ioccur.el b/ioccur.el
index 93e1d8c..2a03525 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -133,14 +133,14 @@ Special commands:
   "Return next elm of ITERATOR."
   (funcall iterator))
 
-(defsubst* ioccur-iter-position (item seq &key (test 'eq))
+(defsubst* ioccur-position (item seq &key (test 'eq))
   "A simple replacement of CL `position'."
   (loop for i in seq for index from 0
      when (funcall test i item) return index))
 
 (defun* ioccur-iter-sub-next (seq elm &key (test 'eq))
   "Create iterator from position of ELM to end of SEQ."
-  (lexical-let* ((pos      (ioccur-iter-position elm seq :test test))
+  (lexical-let* ((pos      (ioccur-position elm seq :test test))
                  (sub      (nthcdr (1+ pos) seq))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
@@ -149,7 +149,7 @@ Special commands:
 (defun* ioccur-iter-sub-prec (seq elm &key (test 'eq))
   "Create iterator from position of ELM to beginning of SEQ."
   (lexical-let* ((rev-seq  (reverse seq))
-                 (pos      (ioccur-iter-position elm rev-seq :test test))
+                 (pos      (ioccur-position elm rev-seq :test test))
                  (sub      (nthcdr (1+ pos) rev-seq))
                  (iterator (ioccur-iter-list sub)))
      (lambda ()
@@ -493,7 +493,7 @@ for commands provided in the search buffer."
                         (string= ioccur-search-pattern ""))
               (push ioccur-search-pattern ioccur-history))
             ;; If elm already exists in history ring push it on top of stack.
-            (let ((pos-hist-elm (ioccur-iter-position ioccur-search-pattern
+            (let ((pos-hist-elm (ioccur-position ioccur-search-pattern
                                                ioccur-history :test 'equal)))
               (unless (string= (car ioccur-history)
                                ioccur-search-pattern)

commit ce05b32400faa225d632597c17c7a6ab688e2597
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:25:53 2010 -0800

    debug mode, t for now

diff --git a/README.md b/README.md
index 90f7d5a..0e4a31f 100644
--- a/README.md
+++ b/README.md
@@ -167,6 +167,7 @@ Naturally. Example:
     (defun coffee-custom ()
       "coffee-mode-hook"
       (set (make-local-variable 'tab-width) 2)
+      (setq coffee-debug-mode t)
       (setq coffee-command "~/dev/coffee))
 
     (add-hook coffee-mode-hook
diff --git a/coffee-mode.el b/coffee-mode.el
index b1473f5..b96e01a 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -58,6 +58,9 @@
 (defconst coffee-mode-version "0.1.0"
   "The version of this `coffee-mode'.")
 
+(defvar coffee-debug-mode t
+  "Whether to run in debug mode or not. Logs to `*Messages*'.")
+
 (defvar coffee-mode-hook nil
   "A hook for you to run your own code when the mode is loaded.")
 
@@ -223,6 +226,11 @@ For detail, see `comment-dwim'."
   (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
     (comment-dwim arg)))
 
+(defun coffee-debug (string &optional args)
+  "Print a message when in debug mode."
+  (when coffee-debug-mode
+      (message string args)))
+
 ;;
 ;; Indentation
 ;;
@@ -238,13 +246,16 @@ For detail, see `comment-dwim'."
       ;; Figure out the indentation of the previous line
       (forward-line -1)
       (setq prev-indent (current-indentation))
+      (coffee-debug "prev-indent %s" prev-indent)
 
       ;; Figure out the current line's indentation
       (forward-line 1)
       (setq cur-indent (current-indentation))
+      (coffee-debug "cur-indent %s" cur-indent)
 
       ;; Shift one column to the left
       (backward-to-indentation 0)
+      (coffee-debug "backward cur-indent %s" (current-indentation))
       (insert-tab)
 
       ;; We're too far, remove all indentation.

commit 14ab5a072a86f08a56b30b5c3f0ecd4c92aac06c
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:20:02 2010 -0800

    Use Common Lisp's `some` despite its inferior API.

diff --git a/coffee-mode.el b/coffee-mode.el
index e59e3d1..b1473f5 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -49,6 +49,7 @@
 
 (require 'easymenu)
 (require 'font-lock)
+(require 'cl)
 
 ;;
 ;; Customizable Variables
@@ -312,9 +313,9 @@ line? Returns `t' or `nil'. See the README for more 
details."
         (end-of-line)
 
         ;; Optimized for speed - checks only the last character.
-        (when (select coffee-indenters-eol
-                      (lambda (char)
-                        (= (char-before) char)))
+        (when (some (lambda (char)
+                        (= (char-before) char))
+                      coffee-indenters-eol)
           (setq indenter-at-eol t)))
 
       ;; If we found an indenter, return `t'.

commit f4d2c54a2c6f82029cb9152ecf2e881b94436969
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:14:46 2010 -0800

    yeah

diff --git a/README.md b/README.md
index 1a979b2..90f7d5a 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,8 @@ In other words, the level of indentation is maintained. This
 applies to comments as well. Combined with the `TAB` you should be
 able to get things where you want them pretty easily.
 
+### Indenters
+
 `class`, `for`, `if`, and possibly other keywords cause the next line
 to be indented automatically, however.
 
diff --git a/coffee-mode.el b/coffee-mode.el
index 31f97f8..e59e3d1 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -320,8 +320,6 @@ line? Returns `t' or `nil'. See the README for more 
details."
       ;; If we found an indenter, return `t'.
       (or indenter-at-bol indenter-at-eol))))
 
-(define-key global-map (kbd "A-d") 'coffee-line-wants-indent)
-
 (defun coffee-previous-line-is-comment ()
   "Returns `t' if the previous line is a CoffeeScript comment."
   (save-excursion

commit df0818671f63ec42d65c2b327f485e041628b7f0
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:13:45 2010 -0800

    indenters

diff --git a/README.md b/README.md
index 8ecf2b5..1a979b2 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ current line more than two indentation levels deepers than the
 previous line. If that's the case, remove all indentation.
 
 Consider this code, with point at the position indicated by the
-carot:
+caret:
 
     line1()
       line2()
@@ -77,7 +77,8 @@ indentation with a whitespace-sensitive
 
 ### Newline and Indent
 
-As for indentation after newlines, given this code:
+As for indentation after newlines, given this code and cursor
+position:
 
     line1()
       line2()
@@ -97,6 +98,38 @@ In other words, the level of indentation is maintained. This
 applies to comments as well. Combined with the `TAB` you should be
 able to get things where you want them pretty easily.
 
+`class`, `for`, `if`, and possibly other keywords cause the next line
+to be indented automatically, however.
+
+For example, given this code and cursor position::
+
+    class Animal
+                ^
+
+Pressing enter would produce the following:
+
+    class Animal
+
+      ^
+
+That is, indented a column deeper.
+
+This also applies to lines ending in `->`, `=>`, `{`, `[`, and
+possibly more characters.
+
+So this code and cursor position:
+
+    $('#demo').click ->
+                       ^
+
+On enter would produce this:
+
+    $('#demo').click ->
+
+      ^
+
+Pretty slick.
+
 ## Commands
 
 ### coffee-compile-buffer
diff --git a/coffee-mode.el b/coffee-mode.el
index 0c2bab2..31f97f8 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -250,6 +250,7 @@ For detail, see `comment-dwim'."
       (when (> (- (current-indentation) prev-indent) tab-width)
         (backward-to-indentation 0)
         (delete-region (point-at-bol) (point))))))
+
 (defun coffee-newline-and-indent ()
   "Inserts a newline and indents it to the same level as the previous line."
   (interactive)
@@ -290,23 +291,7 @@ should probably be indented.")
 
 (defun coffee-line-wants-indent ()
   "Does the current line want to be indented deeper than the previous
-line? Returns `t' or `nil'.
-
-The answer is determined by checking the `coffee-indenters-bol' and
-his friends. Consider this code with the point at the location
-indicated by the caret:
-
-class Animal
-            ^
-
-Pressing RET here should produce the following:
-
-
-class Animal
-
-  ^
-
-Ready and waiting at the proper level of indentation."
+line? Returns `t' or `nil'. See the README for more details."
   (interactive)
 
   (save-excursion

commit 9c51a0a09ad1946ea5d4a468278800d61da78469
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 12:05:56 2010 +0100

    Finally get rid of subseq, rename iter function with ioccur prefix.

diff --git a/ioccur.el b/ioccur.el
index d5323fd..93e1d8c 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -121,7 +121,7 @@ Special commands:
         (kill-local-variable 'mode-line-format)))
 
 ;;; Iterators.
-(defmacro iter-list (list-obj)
+(defmacro ioccur-iter-list (list-obj)
   "Return an iterator from list LIST-OBJ."
   `(lexical-let ((lis ,list-obj))
      (lambda ()
@@ -129,30 +129,31 @@ Special commands:
          (setq lis (cdr lis))
          elm))))
 
-(defun iter-next (iterator)
+(defun ioccur-iter-next (iterator)
   "Return next elm of ITERATOR."
   (funcall iterator))
 
-(defsubst* iter-position (item seq &key (test 'eq))
+(defsubst* ioccur-iter-position (item seq &key (test 'eq))
   "A simple replacement of CL `position'."
   (loop for i in seq for index from 0
      when (funcall test i item) return index))
 
-(defun* iter-sub-next (seq elm &key (test 'eq))
+(defun* ioccur-iter-sub-next (seq elm &key (test 'eq))
   "Create iterator from position of ELM to end of SEQ."
-  (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (subseq seq (1+ pos)))
-                 (iterator (iter-list sub)))
+  (lexical-let* ((pos      (ioccur-iter-position elm seq :test test))
+                 (sub      (nthcdr (1+ pos) seq))
+                 (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (iter-next iterator))))
+       (ioccur-iter-next iterator))))
 
-(defun* iter-sub-prec (seq elm &key (test 'eq))
+(defun* ioccur-iter-sub-prec (seq elm &key (test 'eq))
   "Create iterator from position of ELM to beginning of SEQ."
-  (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (reverse (subseq seq 0 pos)))
-                 (iterator (iter-list sub)))
+  (lexical-let* ((rev-seq  (reverse seq))
+                 (pos      (ioccur-iter-position elm rev-seq :test test))
+                 (sub      (nthcdr (1+ pos) rev-seq))
+                 (iterator (ioccur-iter-list sub)))
      (lambda ()
-       (iter-next iterator))))
+       (ioccur-iter-next iterator))))
 
 (defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'file))
   "Return an alist of all the (num-line line) of a file or buffer BFILE 
matching REGEXP."
@@ -277,7 +278,7 @@ Special commands:
   (let* ((prompt         (propertize ioccur-search-prompt 'face 
'minibuffer-prompt))
          (inhibit-quit   (not (fboundp 'read-key)))
          (tmp-list       ())
-         (it             (iter-list ioccur-history))
+         (it             (ioccur-iter-list ioccur-history))
          (cur-hist-elm   (car ioccur-history))
          (start-hist     nil) ; Flag to notify if cycling history started.
          (old-yank-point start-point)
@@ -293,20 +294,20 @@ Special commands:
                    ;; starting at the current element of history.
                    (when start-hist
                      (if (< arg 0) ; M-p (move from left to right in ring).
-                         (setq it (iter-sub-next ioccur-history
-                                                 cur-hist-elm :test 'equal))
-                         (setq it (iter-sub-prec ioccur-history
-                                                 cur-hist-elm :test 'equal))))
+                         (setq it (ioccur-iter-sub-next ioccur-history
+                                                        cur-hist-elm :test 
'equal))
+                         (setq it (ioccur-iter-sub-prec ioccur-history
+                                                        cur-hist-elm :test 
'equal))))
                    (setq tmp-list nil)
-                   (let ((next (iter-next it)))
+                   (let ((next (ioccur-iter-next it)))
                      ;; If no more elements in list
                      ;; rebuild a new iterator based on the whole history list
                      ;; and restart from beginning or end of list.
                      (unless next
-                       (setq it (iter-list (if (< arg 0)
+                       (setq it (ioccur-iter-list (if (< arg 0)
                                                ioccur-history
                                                (reverse ioccur-history))))
-                       (setq next (iter-next it)) (setq start-hist nil))
+                       (setq next (ioccur-iter-next it)) (setq start-hist nil))
                      (setq initial-input (or next "")))
                    (unless (string= initial-input "")
                      (loop for char across initial-input do (push char 
tmp-list))
@@ -492,7 +493,7 @@ for commands provided in the search buffer."
                         (string= ioccur-search-pattern ""))
               (push ioccur-search-pattern ioccur-history))
             ;; If elm already exists in history ring push it on top of stack.
-            (let ((pos-hist-elm (iter-position ioccur-search-pattern
+            (let ((pos-hist-elm (ioccur-iter-position ioccur-search-pattern
                                                ioccur-history :test 'equal)))
               (unless (string= (car ioccur-history)
                                ioccur-search-pattern)

commit 5e170be4118309e6138bbecef143f88fecce8db7
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 03:05:47 2010 -0800

    get it working (with a fake function though)

diff --git a/coffee-mode.el b/coffee-mode.el
index 1a4db54..0c2bab2 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -280,17 +280,13 @@ For detail, see `comment-dwim'."
   "Keywords or syntax whose presence at the start of a line means the
 next line should probably be indented.")
 
-(defvar coffee-indenters-eol '("->" "=>" "\\{" "\\[")
-  "Keywords or syntax whose presence at the end of a line means the
-next line should probably be indented.")
-
 (defun coffee-indenters-bol-regexp ()
   "Builds a regexp out of `coffee-indenters-bol' words."
   (concat "^" (regexp-opt coffee-indenters-bol 'words)))
 
-(defun coffee-indenters-eol-regexp ()
-  "Builds a regexp out of `coffee-indenters-eol' words."
-  (regexp-opt coffee-indenters-eol 'words))
+(defvar coffee-indenters-eol '(?> ?{ ?\[)
+  "Single characters at the end of a line that mean the next line
+should probably be indented.")
 
 (defun coffee-line-wants-indent ()
   "Does the current line want to be indented deeper than the previous
@@ -325,23 +321,17 @@ Ready and waiting at the proper level of indentation."
         (setq indenter-at-bol t))
 
       ;; If that didn't match, go to the back of the line and check to
-      ;; see if the last few characters match one of our indenter
-      ;; keywords.
+      ;; see if the last character matches one of our indenter
+      ;; characters.
       (when (not indenter-at-bol)
         (end-of-line)
 
-        ;; Optimized for speed.
-        ;; Check for -> or => by checking for >
-        (when (= (char-before) ?>)
-          (setq indenter-at-eol t))
-
-        ;; If not an arrow, check the rest of the options.
-        (when (and (not indenter-at-eol)
-                   (looking-back (coffee-indenters-eol-regexp)))
+        ;; Optimized for speed - checks only the last character.
+        (when (select coffee-indenters-eol
+                      (lambda (char)
+                        (= (char-before) char)))
           (setq indenter-at-eol t)))
 
-      (message "indenter-at-eol: %s" indenter-at-eol)
-
       ;; If we found an indenter, return `t'.
       (or indenter-at-bol indenter-at-eol))))
 

commit 17150cf28750527c350166b6db984ab042d9c534
Author: Chris Wanstrath <address@hidden>
Date:   Sun Mar 7 02:24:28 2010 -0800

    docs and starting to implement indenters

diff --git a/coffee-mode.el b/coffee-mode.el
index ebb0285..1a4db54 100644
--- a/coffee-mode.el
+++ b/coffee-mode.el
@@ -92,21 +92,21 @@ print the compiled JavaScript.")
   "Launch a CoffeeScript REPL using `coffee-command' as an inferior mode."
   (interactive)
 
-  (unless (comint-check-proc "*CoffeeScript*")
+  (unless (comint-check-proc "*CoffeeREPL*")
     (set-buffer
-     (apply 'make-comint "CoffeeScript"
+     (apply 'make-comint "CoffeeREPL"
             coffee-command nil coffee-repl-args)))
 
   (pop-to-buffer "*CoffeeScript*"))
 
 (defun coffee-compile-buffer ()
-  "Compiles the current buffer and displays the JS in the other buffer."
+  "Compiles the current buffer and displays the JS in another buffer."
   (interactive)
   (save-excursion
     (coffee-compile-region (point-min) (point-max))))
 
 (defun coffee-compile-region (start end)
-  "Compiles a region and displays the JS in the other buffer."
+  "Compiles a region and displays the JS in another buffer."
   (interactive "r")
 
   (let ((buffer (get-buffer coffee-compiled-buffer-name)))
@@ -250,12 +250,37 @@ For detail, see `comment-dwim'."
       (when (> (- (current-indentation) prev-indent) tab-width)
         (backward-to-indentation 0)
         (delete-region (point-at-bol) (point))))))
+(defun coffee-newline-and-indent ()
+  "Inserts a newline and indents it to the same level as the previous line."
+  (interactive)
+
+  ;; Remember the current line indentation level,
+  ;; insert a newline, and indent the newline to the same
+  ;; level as the previous line.
+  (let ((prev-indent (current-indentation)) (indent-next nil))
+    (newline)
+    (insert-tab (/ prev-indent tab-width))
 
-(defvar coffee-indenters-bol '("class" "for" "if")
+    ;; We need to insert an additional tab because the last line was special.
+    (when (coffee-line-wants-indent)
+      (insert-tab)))
+
+  ;; Last line was a comment so this one should probably be,
+  ;; too. Makes it easy to write multi-line comments (like the one I'm
+  ;; writing right now).
+  (when (coffee-previous-line-is-comment)
+    (insert "# ")))
+
+;; Indenters help determine whether the current line should be
+;; indented further based on the content of the previous line. If a
+;; line starts with `class', for instance, you're probably going to
+;; want to indent the next line.
+
+(defvar coffee-indenters-bol '("class" "for" "if" "try")
   "Keywords or syntax whose presence at the start of a line means the
 next line should probably be indented.")
 
-(defvar coffee-indenters-eol '("->" "=>" "{" "[")
+(defvar coffee-indenters-eol '("->" "=>" "\\{" "\\[")
   "Keywords or syntax whose presence at the end of a line means the
 next line should probably be indented.")
 
@@ -265,21 +290,62 @@ next line should probably be indented.")
 
 (defun coffee-indenters-eol-regexp ()
   "Builds a regexp out of `coffee-indenters-eol' words."
-  (concat (regexp-opt coffee-indenters-eol 'words) "$"))
+  (regexp-opt coffee-indenters-eol 'words))
 
-(defun coffee-newline-and-indent ()
-  "Inserts a newline and indents it to the same level as the previous line."
+(defun coffee-line-wants-indent ()
+  "Does the current line want to be indented deeper than the previous
+line? Returns `t' or `nil'.
+
+The answer is determined by checking the `coffee-indenters-bol' and
+his friends. Consider this code with the point at the location
+indicated by the caret:
+
+class Animal
+            ^
+
+Pressing RET here should produce the following:
+
+
+class Animal
+
+  ^
+
+Ready and waiting at the proper level of indentation."
   (interactive)
 
-  ;; Remember the current line indentation level,
-  ;; insert a newline, and indent the newline to the same
-  ;; level as the previous line.
-  (let ((prev-indent (current-indentation)))
-    (newline)
-    (insert-tab (/ prev-indent tab-width)))
+  (save-excursion
+    (let ((indenter-at-bol) (indenter-at-eol))
+      ;; Go back a line and to the first character.
+      (forward-line -1)
+      (backward-to-indentation 0)
 
-  (when (coffee-previous-line-is-comment)
-    (insert "# ")))
+      ;; If the next few characters match one of our magic indenter
+      ;; keywords, we want to indent the line we were on originally.
+      (when (looking-at (coffee-indenters-bol-regexp))
+        (setq indenter-at-bol t))
+
+      ;; If that didn't match, go to the back of the line and check to
+      ;; see if the last few characters match one of our indenter
+      ;; keywords.
+      (when (not indenter-at-bol)
+        (end-of-line)
+
+        ;; Optimized for speed.
+        ;; Check for -> or => by checking for >
+        (when (= (char-before) ?>)
+          (setq indenter-at-eol t))
+
+        ;; If not an arrow, check the rest of the options.
+        (when (and (not indenter-at-eol)
+                   (looking-back (coffee-indenters-eol-regexp)))
+          (setq indenter-at-eol t)))
+
+      (message "indenter-at-eol: %s" indenter-at-eol)
+
+      ;; If we found an indenter, return `t'.
+      (or indenter-at-bol indenter-at-eol))))
+
+(define-key global-map (kbd "A-d") 'coffee-line-wants-indent)
 
 (defun coffee-previous-line-is-comment ()
   "Returns `t' if the previous line is a CoffeeScript comment."
diff --git a/examples/basic.coffee b/examples/basic.coffee
index 6ca01aa..d183fa6 100644
--- a/examples/basic.coffee
+++ b/examples/basic.coffee
@@ -59,6 +59,11 @@ class Horse extends Animal
 sam: new Snake "Sammy the Python"
 tom: new Horse "Tommy the Palomino"
 
+
+
+
+
+
 sam.move()
 tom.move()
 if car.speed < speed_limit then accelerate()
@@ -84,8 +89,20 @@ alert "Silver: " + silver
 alert "The Field: " + the_field
 
 # Eat lunch.
+# what up
+# love it.
 lunch: eat food for food in ['toast', 'cheese', 'wine']
 
+$('#demo').click ->
+  asd
+# sup
+  # asd
+  # asdasd
+blah: true
+
+okay
+
+
 # Naive collision detection.
 for roid in asteroids
   for roid2 in asteroids when roid isnt roid2
diff --git a/test.coffee b/test.coffee
new file mode 100644
index 0000000..c74e1af
--- /dev/null
+++ b/test.coffee
@@ -0,0 +1,26 @@
+Person: {
+  hi: "world"
+
+  world: "hi"
+}
+
+hi: "mom"
+
+Person: {
+
+
+
+class Dog
+  constructor: (hey) =>
+
+
+
+
+
+
+
+
+
+
+
+

commit 779c09aa1d951e3a349980c690a79c1f23aa27a8
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 11:07:23 2010 +0100

    (iter-sub-prec): Bugfix with nthcdr, finally fallback to subseq.

diff --git a/ioccur.el b/ioccur.el
index 1fd6060..d5323fd 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -141,7 +141,7 @@ Special commands:
 (defun* iter-sub-next (seq elm &key (test 'eq))
   "Create iterator from position of ELM to end of SEQ."
   (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (nthcdr (1+ pos) seq))
+                 (sub      (subseq seq (1+ pos)))
                  (iterator (iter-list sub)))
      (lambda ()
        (iter-next iterator))))
@@ -149,7 +149,7 @@ Special commands:
 (defun* iter-sub-prec (seq elm &key (test 'eq))
   "Create iterator from position of ELM to beginning of SEQ."
   (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (nthcdr pos (reverse seq)))
+                 (sub      (reverse (subseq seq 0 pos)))
                  (iterator (iter-list sub)))
      (lambda ()
        (iter-next iterator))))

commit fed894770446ca39815bb96ad7f64bd1ab980333
Author: Thierry Volpiatto <address@hidden>
Date:   Sun Mar 7 09:05:55 2010 +0100

    Store maxi `ioccur-max-length-history' elements in history.
    
    (ioccur): max elements in history
    (ioccur-max-length-history): set maximum number of elements stored in 
history
    (ioccur-num-line-face): new face

diff --git a/ioccur.el b/ioccur.el
index 40d541c..1fd6060 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -46,6 +46,7 @@
   :prefix "ioccur-"
   :group 'text)
 
+;;; User variables.
 (defcustom ioccur-search-delay 0.2
   "*During incremental searching, display is updated all these seconds."
   :group 'ioccur
@@ -69,6 +70,12 @@ If you use this you will want maybe to set 
`ioccur-docstring' to nil"
   :group 'ioccur
   :type 'integer)
 
+(defcustom ioccur-max-length-history 100
+  "*Maximum number of element stored in `ioccur-history'."
+  :group 'ioccur
+  :type 'integer)
+
+;;; Faces.
 (defface ioccur-overlay-face '((t (:background "Green4" :underline t)))
   "Face for highlight line in ioccur buffer."
   :group 'ioccur-faces)
@@ -85,10 +92,11 @@ If you use this you will want maybe to set 
`ioccur-docstring' to nil"
   "Face for highlight found regexp in incremental buffer."
   :group 'ioccur-faces)
 
-(defvar ioccur-face 'ioccur-overlay-face)
-(defvar ioccur-match-face 'ioccur-match-overlay-face)
+(defface ioccur-num-line-face '((t (:foreground "OrangeRed")))
+  "Face for highlight number line in ioccur buffer."
+  :group 'ioccur-faces)
 
-;;; Internal variables
+;;; Internal variables.
 (defvar ioccur-search-pattern "")
 (defvar ioccur-search-timer nil)
 (defvar ioccur-quit-flag nil)
@@ -97,8 +105,8 @@ If you use this you will want maybe to set 
`ioccur-docstring' to nil"
 (defvar ioccur-exit-and-quit-p nil)
 (defvar ioccur-history nil)
 (defvar ioccur-match-overlay nil)
-(defvar ioccur-count-occurences 0
-  "Simple variable to store the number of occurence found.")
+(defvar ioccur-count-occurences 0)
+  
 
 (define-derived-mode ioccur-mode
     text-mode "ioccur"
@@ -112,7 +120,7 @@ Special commands:
                 (line-number-mode "%l") " " ioccur-mode-line-string "-%-"))
         (kill-local-variable 'mode-line-format)))
 
-;; Iterators
+;;; Iterators.
 (defmacro iter-list (list-obj)
   "Return an iterator from list LIST-OBJ."
   `(lexical-let ((lis ,list-obj))
@@ -122,8 +130,7 @@ Special commands:
          elm))))
 
 (defun iter-next (iterator)
-  "Return next elm of ITERATOR.
-create ITERATOR with `iter-list'."
+  "Return next elm of ITERATOR."
   (funcall iterator))
 
 (defsubst* iter-position (item seq &key (test 'eq))
@@ -175,7 +182,7 @@ create ITERATOR with `iter-list'."
                (line-to-print new-ltp))
           (incf ioccur-count-occurences)
           (insert (concat " " (propertize (int-to-string (+ (first i) 1))
-                                          'face 'ioccur-match-face
+                                          'face 'ioccur-num-line-face
                                           'help-echo line-to-print)
                           ":"
                           (if (> (length line-to-print) lline)
@@ -413,6 +420,7 @@ create ITERATOR with `iter-list'."
               ioccur-search-pattern
               ioccur-current-buffer)))))
 
+
 ;;;###autoload
 (defun ioccur (&optional initial-input)
   "Incremental search of lines in current buffer matching input.
@@ -489,7 +497,9 @@ for commands provided in the search buffer."
               (unless (string= (car ioccur-history)
                                ioccur-search-pattern)
                 (push (pop (nthcdr pos-hist-elm ioccur-history))
-                      ioccur-history))))
+                      ioccur-history)))
+            (when (> (length ioccur-history) ioccur-max-length-history)
+              (setq ioccur-history (delete (car (last ioccur-history)) 
ioccur-history))))
         (setq ioccur-count-occurences 0)
         (setq ioccur-quit-flag nil)))))
 
@@ -510,7 +520,7 @@ for commands provided in the search buffer."
       (move-overlay ioccur-occur-overlay
                     (line-beginning-position) (1+ (line-end-position))))
   (overlay-put ioccur-occur-overlay
-               'face ioccur-face))
+               'face 'ioccur-overlay-face))
 
 (defun ioccur-color-matched-line ()
   "Highlight and current position on matched line."
@@ -521,7 +531,7 @@ for commands provided in the search buffer."
       (move-overlay ioccur-match-overlay
                     (line-beginning-position) (1+ (line-end-position))))
   (overlay-put ioccur-match-overlay
-               'face ioccur-match-face))
+               'face 'ioccur-match-overlay-face))
 
 ;;; Provide
 (provide 'ioccur)

commit 09c57eccc785df70425ee08aaa24d37e39dbb46b
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 6 22:28:48 2010 +0100

    (iter-sub-prec/next): Use nthcdr instead of subseq.

diff --git a/ioccur.el b/ioccur.el
index 44779f8..40d541c 100644
--- a/ioccur.el
+++ b/ioccur.el
@@ -134,7 +134,7 @@ create ITERATOR with `iter-list'."
 (defun* iter-sub-next (seq elm &key (test 'eq))
   "Create iterator from position of ELM to end of SEQ."
   (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (subseq seq (1+ pos)))
+                 (sub      (nthcdr (1+ pos) seq))
                  (iterator (iter-list sub)))
      (lambda ()
        (iter-next iterator))))
@@ -142,7 +142,7 @@ create ITERATOR with `iter-list'."
 (defun* iter-sub-prec (seq elm &key (test 'eq))
   "Create iterator from position of ELM to beginning of SEQ."
   (lexical-let* ((pos      (iter-position elm seq :test test))
-                 (sub      (reverse (subseq seq 0 pos)))
+                 (sub      (nthcdr pos (reverse seq)))
                  (iterator (iter-list sub)))
      (lambda ()
        (iter-next iterator))))

commit ed2b0371ae687d373a2c56e53df9a27034380535
Author: Thierry Volpiatto <address@hidden>
Date:   Sat Mar 6 16:47:13 2010 +0100

    Initial commit.

diff --git a/ioccur.el b/ioccur.el
new file mode 100644
index 0000000..44779f8
--- /dev/null
+++ b/ioccur.el
@@ -0,0 +1,529 @@
+;;; ioccur.el --- Incremental occur.
+
+;; Author: Thierry Volpiatto
+
+;; Copyright (C) 2010 Thierry Volpiatto, all rights reserved.
+
+;; Compatibility: GNU Emacs 23.1+
+
+;; This file is not part of GNU Emacs. 
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 3, or
+;; (at your option) any later version.
+;; 
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;; 
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
+;; Floor, Boston, MA 02110-1301, USA.
+
+;;; Code:
+(require 'derived)
+(eval-when-compile (require 'cl))
+
+(defvar ioccur-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "q") 'ioccur-quit)
+    (define-key map (kbd "RET") 'ioccur-jump-and-quit)
+    (define-key map (kbd "<C-down>") 'ioccur-scroll-down)
+    (define-key map (kbd "<C-up>") 'ioccur-scroll-up)
+    (define-key map (kbd "<down>") 'ioccur-next-line)
+    (define-key map (kbd "<up>") 'ioccur-precedent-line)
+    (define-key map (kbd "C-n") 'ioccur-next-line)
+    (define-key map (kbd "C-p") 'ioccur-precedent-line)
+    map)
+  "Keymap used for ioccur commands.")
+
+
+(defgroup ioccur nil
+  "Mode that provide incremental searching in buffer."
+  :prefix "ioccur-"
+  :group 'text)
+
+(defcustom ioccur-search-delay 0.2
+  "*During incremental searching, display is updated all these seconds."
+  :group 'ioccur
+  :type  'integer)
+
+(defcustom ioccur-search-prompt "Pattern: "
+  "*Prompt used for `ioccur-occur'."
+  :group 'ioccur
+  :type  'string)
+
+(defcustom ioccur-mode-line-string
+  " RET:Exit, C-g:Quit, C-k:Kill, C-z:Jump, C-j:Jump&quit, 
C-n/p:Next/Prec-line, M-p/n:Hist, C/M-v C-down/up:Scroll, C-w:Yank tap"
+  "*Documentation of `ioccur-occur' prompt displayed in mode-line.
+Set it to nil to remove doc in mode-line.
+If you use this you will want maybe to set `ioccur-docstring' to nil"
+  :group 'ioccur
+  :type  'string)
+
+(defcustom ioccur-length-line 80
+  "*Length of the line displayed in ioccur buffer."
+  :group 'ioccur
+  :type 'integer)
+
+(defface ioccur-overlay-face '((t (:background "Green4" :underline t)))
+  "Face for highlight line in ioccur buffer."
+  :group 'ioccur-faces)
+
+(defface ioccur-match-overlay-face '((t (:background "Indianred4" :underline 
t)))
+  "Face for highlight line in matched buffer."
+  :group 'ioccur-faces)
+
+(defface ioccur-title-face '((t (:background "Dodgerblue4")))
+  "Face for highlight incremental buffer title."
+  :group 'ioccur-faces)
+
+(defface ioccur-regexp-face '((t (:background "DeepSkyBlue" :underline t)))
+  "Face for highlight found regexp in incremental buffer."
+  :group 'ioccur-faces)
+
+(defvar ioccur-face 'ioccur-overlay-face)
+(defvar ioccur-match-face 'ioccur-match-overlay-face)
+
+;;; Internal variables
+(defvar ioccur-search-pattern "")
+(defvar ioccur-search-timer nil)
+(defvar ioccur-quit-flag nil)
+(defvar ioccur-current-buffer nil)
+(defvar ioccur-occur-overlay nil)
+(defvar ioccur-exit-and-quit-p nil)
+(defvar ioccur-history nil)
+(defvar ioccur-match-overlay nil)
+(defvar ioccur-count-occurences 0
+  "Simple variable to store the number of occurence found.")
+
+(define-derived-mode ioccur-mode
+    text-mode "ioccur"
+    "Major mode to search occurences of regexp in current buffer.
+
+Special commands:
+\\{ioccur-mode-map}"
+    (if ioccur-mode-line-string
+        (setq mode-line-format
+              '(" " mode-line-buffer-identification " "
+                (line-number-mode "%l") " " ioccur-mode-line-string "-%-"))
+        (kill-local-variable 'mode-line-format)))
+
+;; Iterators
+(defmacro iter-list (list-obj)
+  "Return an iterator from list LIST-OBJ."
+  `(lexical-let ((lis ,list-obj))
+     (lambda ()
+       (let ((elm (car lis)))
+         (setq lis (cdr lis))
+         elm))))
+
+(defun iter-next (iterator)
+  "Return next elm of ITERATOR.
+create ITERATOR with `iter-list'."
+  (funcall iterator))
+
+(defsubst* iter-position (item seq &key (test 'eq))
+  "A simple replacement of CL `position'."
+  (loop for i in seq for index from 0
+     when (funcall test i item) return index))
+
+(defun* iter-sub-next (seq elm &key (test 'eq))
+  "Create iterator from position of ELM to end of SEQ."
+  (lexical-let* ((pos      (iter-position elm seq :test test))
+                 (sub      (subseq seq (1+ pos)))
+                 (iterator (iter-list sub)))
+     (lambda ()
+       (iter-next iterator))))
+
+(defun* iter-sub-prec (seq elm &key (test 'eq))
+  "Create iterator from position of ELM to beginning of SEQ."
+  (lexical-let* ((pos      (iter-position elm seq :test test))
+                 (sub      (reverse (subseq seq 0 pos)))
+                 (iterator (iter-list sub)))
+     (lambda ()
+       (iter-next iterator))))
+
+(defsubst* ioccur-find-readlines (bfile regexp &key (insert-fn 'file))
+  "Return an alist of all the (num-line line) of a file or buffer BFILE 
matching REGEXP."
+  (let ((count 0)
+        (fn    (case insert-fn
+                 ('file 'insert-file-contents)
+                 ('buffer 'insert-buffer-substring))))
+    (with-temp-buffer
+      (funcall fn bfile) ; call insert function
+      (goto-char (point-min))
+      (loop
+         with lines-list = (split-string (buffer-string) "\n")
+         for i in lines-list when (string-match regexp i)
+         collect (list count (replace-regexp-in-string "\n" "" i)) into lis
+         do (incf count)
+         finally return lis))))
+
+(defun* ioccur-buffer-process-ext (regex buffer &key (lline 
ioccur-length-line))
+  "Function to process buffer in external program like anything."
+  (setq ioccur-count-occurences 0)
+  (let ((matched-lines (ioccur-find-readlines buffer regex :insert-fn 
'buffer)))
+    (when matched-lines
+      (dolist (i matched-lines) ; Each element is of the form '(key value)
+        (let* ((ltp           (second i))
+               (replace-reg   (if (string-match "^\t" ltp) "\\(^\t*\\)" "\\(^ 
*\\)"))
+               (new-ltp       (replace-regexp-in-string replace-reg "" ltp))
+               (line-to-print new-ltp))
+          (incf ioccur-count-occurences)
+          (insert (concat " " (propertize (int-to-string (+ (first i) 1))
+                                          'face 'ioccur-match-face
+                                          'help-echo line-to-print)
+                          ":"
+                          (if (> (length line-to-print) lline)
+                              (substring line-to-print 0 lline)
+                              line-to-print)
+                          "\n")))))))
+
+(defun ioccur-quit ()
+  "Quit and kill ioccur buffer."
+  (interactive)
+  (when ioccur-match-overlay
+    (delete-overlay ioccur-match-overlay))
+  (quit-window t)
+  (other-window 1)
+  (delete-other-windows))
+
+(defun ioccur-goto-line (numline)
+  "Non--interactive version of `goto-line.'"
+  (goto-char (point-min)) (forward-line (1- numline)))
+
+(defun ioccur-forward-line (n)
+  "Forward line only if it is not an empty line."
+  (let (pos)
+    (save-excursion
+      (forward-line n) (forward-line 0)
+      (when (looking-at "^ [0-9]+") (forward-line 0) (setq pos (point))))
+  (when pos (goto-char pos) (ioccur-color-current-line))))
+
+;;;###autoload
+(defun ioccur-next-line ()
+  "Goto next line if it is not an empty line."
+  (interactive)
+  (ioccur-forward-line 1))
+
+;;;###autoload
+(defun ioccur-precedent-line ()
+  "Goto precedent line if it is not an empty line."
+  (interactive)
+  (ioccur-forward-line -1))
+
+(defun ioccur-jump ()
+  "Jump to line in other buffer and put an overlay on it."
+  (let ((line (buffer-substring (point-at-bol) (point-at-eol)))
+        pos)
+    (unless (or (string= line "")
+                (string= line "Ioccur"))
+      (when (string-match "[0-9]+" line)
+        (setq pos (string-to-number (match-string 0 line))))
+      (pop-to-buffer ioccur-current-buffer)
+      (ioccur-goto-line pos) (ioccur-color-matched-line))))
+
+
+;;;###autoload
+(defun ioccur-jump-and-quit ()
+  "Jump to line in other buffer and quit search buffer."
+  (interactive)
+  (when (ioccur-jump)
+    (delete-other-windows)
+    (sit-for 0.3)
+    (when ioccur-match-overlay
+      (delete-overlay ioccur-match-overlay))))
+
+(defun ioccur-scroll (n)
+  "Scroll other buffer and move overlay accordingly."
+  (ioccur-forward-line n)
+  (ioccur-color-current-line)
+  (when (ioccur-jump)
+    (other-window 1)))
+
+;;;###autoload
+(defun ioccur-scroll-down ()
+  "Scroll other buffer down."
+  (interactive)
+  (ioccur-scroll 1))
+
+;;;###autoload
+(defun ioccur-scroll-up ()
+  "Scroll other buffer up."
+  (interactive)
+  (ioccur-scroll -1))
+
+(defun ioccur-read-char-or-event (prompt)
+  "Read keyboard input with `read-char' and `read-event' if `read-key' not 
available."
+  (if (fboundp 'read-key)
+      (read-key prompt)
+      (let* ((chr (condition-case nil (read-char prompt) (error nil)))
+             (evt (unless chr (read-event))))
+        (or chr evt))))
+
+(defun ioccur-read-search-input (initial-input start-point)
+  "Read each keyboard input and add it to `ioccur-search-pattern'."
+  (let* ((prompt         (propertize ioccur-search-prompt 'face 
'minibuffer-prompt))
+         (inhibit-quit   (not (fboundp 'read-key)))
+         (tmp-list       ())
+         (it             (iter-list ioccur-history))
+         (cur-hist-elm   (car ioccur-history))
+         (start-hist     nil) ; Flag to notify if cycling history started.
+         (old-yank-point start-point)
+         yank-point)
+    (unless (string= initial-input "")
+      (loop for char across initial-input do (push char tmp-list)))
+    (setq ioccur-search-pattern initial-input)
+    (flet ((cycle-hist (arg)
+             (if ioccur-history
+                 (progn
+                   ;; Cycle history started
+                   ;; We build a new iterator based on a sublist
+                   ;; starting at the current element of history.
+                   (when start-hist
+                     (if (< arg 0) ; M-p (move from left to right in ring).
+                         (setq it (iter-sub-next ioccur-history
+                                                 cur-hist-elm :test 'equal))
+                         (setq it (iter-sub-prec ioccur-history
+                                                 cur-hist-elm :test 'equal))))
+                   (setq tmp-list nil)
+                   (let ((next (iter-next it)))
+                     ;; If no more elements in list
+                     ;; rebuild a new iterator based on the whole history list
+                     ;; and restart from beginning or end of list.
+                     (unless next
+                       (setq it (iter-list (if (< arg 0)
+                                               ioccur-history
+                                               (reverse ioccur-history))))
+                       (setq next (iter-next it)) (setq start-hist nil))
+                     (setq initial-input (or next "")))
+                   (unless (string= initial-input "")
+                     (loop for char across initial-input do (push char 
tmp-list))
+                     (setq cur-hist-elm initial-input))
+                   (setq ioccur-search-pattern initial-input)
+                   (setq start-hist t))
+                 (message "No history available.") (sit-for 2) t)))
+      (while (let ((char (ioccur-read-char-or-event
+                          (concat prompt ioccur-search-pattern))))
+               (case char
+                 ((down ?\C-n)                 ; Next line.
+                  (when ioccur-search-timer
+                    (ioccur-cancel-search))
+                  (ioccur-next-line)
+                  (ioccur-color-current-line) t)
+                 ((up ?\C-p)                   ; Precedent line.
+                  (when ioccur-search-timer
+                    (ioccur-cancel-search))
+                  (ioccur-precedent-line)
+                  (ioccur-color-current-line) t)
+                 (C-down                       ; Scroll both windows down.
+                  (when ioccur-search-timer
+                    (ioccur-cancel-search))
+                  (ioccur-scroll-down) t)
+                 (C-up                         ; Scroll both windows up.
+                  (when ioccur-search-timer
+                    (ioccur-cancel-search))
+                  (ioccur-scroll-up) t)
+                 ((?\e ?\r) (message nil) nil) ; RET or ESC break and exit 
code.
+                 (?\d                          ; Delete backward with DEL.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (with-current-buffer ioccur-current-buffer
+                    (goto-char old-yank-point)
+                    (setq yank-point old-yank-point))
+                  (pop tmp-list) t)
+                 (?\C-g                        ; Quit and restore buffers.
+                  (setq ioccur-quit-flag t) nil)
+                 ((or right ?\C-z)             ; Persistent action.
+                  (ioccur-jump) (other-window 1) t)
+                 ((left ?\C-j)                 ; Jump to candidate and kill 
search buffer.
+                  (setq ioccur-exit-and-quit-p t) nil)
+                 (?\C-v                        ; Scroll down.
+                  (scroll-other-window 1) t)
+                 (?\C-k                        ; Kill input.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (with-current-buffer ioccur-current-buffer
+                    (goto-char old-yank-point)
+                    (setq yank-point old-yank-point))
+                  (kill-new ioccur-search-pattern)
+                  (setq tmp-list ()) t)
+                 (?\C-w                        ; Yank stuff at point.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (with-current-buffer ioccur-current-buffer
+                    (unless old-yank-point (setq old-yank-point (point)))
+                    (setq yank-point (point))
+                    (forward-word 1)
+                    (setq initial-input (buffer-substring yank-point (point))))
+                  (unless (string= initial-input "")
+                    (loop for char across initial-input do (push char 
tmp-list)))
+                  (setq ioccur-search-pattern initial-input) t)
+                 (?\M-v                        ; Scroll up.
+                  (scroll-other-window -1) t)
+                 (?\M-p                        ; Precedent history elm.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (cycle-hist -1))
+                 (?\M-n                        ; Next history elm.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (cycle-hist 1))
+                 (t                            ; Store character.
+                  (unless ioccur-search-timer
+                    (ioccur-start-timer))
+                  (if (characterp char)
+                      (push char tmp-list)
+                      ;; Else, a non--character event is entered, not listed 
above.
+                      ;; add it to `unread-command-events' and exit (nil) .
+                      (setq unread-command-events
+                            (nconc (mapcar 'identity 
(this-single-command-raw-keys))
+                                   unread-command-events))
+                      nil))))
+        (setq ioccur-search-pattern (apply 'string (reverse tmp-list)))))))
+
+
+(defun ioccur-filter-alist-by-regexp (regexp buffer-name)
+  "Print all lines matching REGEXP in current buffer to buffer BUFFER-NAME."
+  (let ((title (propertize "Ioccur" 'face 'ioccur-title-face)))
+    (if (string= regexp "")
+        (progn (erase-buffer) (insert (concat title "\n\n")))
+        (erase-buffer)
+        (ioccur-buffer-process-ext regexp buffer-name :lline 
ioccur-length-line)
+        (goto-char (point-min))
+        (insert (concat title "\n\n"
+                 (propertize (format "Found %s occurences of " 
ioccur-count-occurences)
+                             'face 'underline)
+                 (propertize regexp 'face 'ioccur-regexp-face)
+                 (propertize (format " in %s" buffer-name) 'face 'underline) 
"\n\n"))
+        (ioccur-color-current-line))))
+
+
+(defun ioccur-start-timer ()
+  "Start ioccur incremental timer."
+  (setq ioccur-search-timer
+        (run-with-idle-timer
+         ioccur-search-delay 'repeat
+         #'(lambda ()
+             (ioccur-filter-alist-by-regexp
+              ioccur-search-pattern
+              ioccur-current-buffer)))))
+
+;;;###autoload
+(defun ioccur (&optional initial-input)
+  "Incremental search of lines in current buffer matching input.
+
+With a prefix arg search symbol at point (INITIAL-INPUT).
+
+While you are incremental searching, commands provided are:
+
+C-n or <down>  next line.
+C-p or <up>    precedent line.
+C-v and M-v    scroll up and down.
+C-z or <right> jump without quitting loop.
+C-j or <left>  jump and exit search buffer.
+RET or ESC     exit but don't quit search buffer.
+DEL            remove last character entered.
+C-k            Kill current input.
+C-w            Yank stuff at point.
+C-g            quit and restore buffer.
+M-p/n          Precedent and next `ioccur-history' element:
+
+M-p ,-->A B C D E F G H I---,
+    |                       |
+    `---I H G F E D C B A<--'
+
+M-n ,-->I H G F E D C B A---,
+    |                       |
+    `---A B C D E F G H I<--'
+
+When you quit incremental search with RET or ESC, see `ioccur-mode'
+for commands provided in the search buffer."
+  (interactive "P")
+  (setq ioccur-exit-and-quit-p nil)
+  (setq ioccur-current-buffer (buffer-name (current-buffer)))
+  (with-current-buffer ioccur-current-buffer
+    (jit-lock-fontify-now))
+  (let* ((init-str (if initial-input (thing-at-point 'symbol) ""))
+         (len      (length init-str))
+         (curpos   (point))
+         str-no-prop)
+    (set-text-properties 0 len nil init-str)
+    (setq str-no-prop init-str)
+    (pop-to-buffer (get-buffer-create "*ioccur*"))
+    (ioccur-mode)
+    (unwind-protect
+         ;; Start incremental search.
+         (progn
+           (ioccur-start-timer)
+           (ioccur-read-search-input str-no-prop curpos))
+      ;; At this point incremental search loop is exited.
+      (progn
+        (ioccur-cancel-search)
+        (kill-local-variable 'mode-line-format)
+        (when (equal (buffer-substring (point-at-bol) (point-at-eol)) "")
+          (setq ioccur-quit-flag t))
+        (if ioccur-quit-flag ; C-g
+            (progn
+              (kill-buffer "*ioccur*")
+              (switch-to-buffer ioccur-current-buffer)
+              (when ioccur-match-overlay
+                (delete-overlay ioccur-match-overlay))
+              (delete-other-windows) (goto-char curpos) (message nil))
+
+            (if ioccur-exit-and-quit-p
+                (progn (ioccur-jump-and-quit)
+                       (kill-buffer "*ioccur*") (message nil))
+                (ioccur-jump) (other-window 1))
+            ;; Push elm in history if not already there or empty.
+            (unless (or (member ioccur-search-pattern ioccur-history)
+                        (string= ioccur-search-pattern ""))
+              (push ioccur-search-pattern ioccur-history))
+            ;; If elm already exists in history ring push it on top of stack.
+            (let ((pos-hist-elm (iter-position ioccur-search-pattern
+                                               ioccur-history :test 'equal)))
+              (unless (string= (car ioccur-history)
+                               ioccur-search-pattern)
+                (push (pop (nthcdr pos-hist-elm ioccur-history))
+                      ioccur-history))))
+        (setq ioccur-count-occurences 0)
+        (setq ioccur-quit-flag nil)))))
+
+
+(defun ioccur-cancel-search ()
+  "Cancel timer used for ioccur searching."
+  (when ioccur-search-timer
+    (cancel-timer ioccur-search-timer)
+    (setq ioccur-search-timer nil)))
+
+
+(defun ioccur-color-current-line ()
+  "Highlight and underline current line in ioccur buffer."
+  (if (not ioccur-occur-overlay)
+      (setq ioccur-occur-overlay
+            (make-overlay
+             (line-beginning-position) (1+ (line-end-position))))
+      (move-overlay ioccur-occur-overlay
+                    (line-beginning-position) (1+ (line-end-position))))
+  (overlay-put ioccur-occur-overlay
+               'face ioccur-face))
+
+(defun ioccur-color-matched-line ()
+  "Highlight and current position on matched line."
+  (if (not ioccur-match-overlay)
+      (setq ioccur-match-overlay
+            (make-overlay
+             (line-beginning-position) (1+ (line-end-position))))
+      (move-overlay ioccur-match-overlay
+                    (line-beginning-position) (1+ (line-end-position))))
+  (overlay-put ioccur-match-overlay
+               'face ioccur-match-face))
+
+;;; Provide
+(provide 'ioccur)
+
+;;; ioccur.el ends here.

commit dc7d01f89b664abcbdf482b9db6e5e8a1a369e04
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Feb 23 00:01:35 2010 +0100

    Bumped version to 0.5.

diff --git a/company-abbrev.el b/company-abbrev.el
index 5c807a3..16cdeed 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-clang.el b/company-clang.el
index c38a043..b054599 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2010 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index b2d4c6a..cb80ce0 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index e66b8ff..93f62c9 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 176a500..c5a6081 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-eclim.el b/company-eclim.el
index 97487fc..8ff0141 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index 4c68cbb..a10fe46 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index 95608a9..eeb7d90 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 8915876..6c0775c 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 2d08035..ed591a0 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index 2a153aa..236c519 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-keywords.el b/company-keywords.el
index d640932..1e86705 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 4fc615c..bacc1dc 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 85e6bfa..67b9a80 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-pysmell.el b/company-pysmell.el
index 6fc3574..4c98f07 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ropemacs.el b/company-ropemacs.el
index b5c97cd..92de7d0 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index e6e4c56..aec05a9 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index 2ce4330..b22e72a 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 1d71a31..396cef8 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.3.
+;; This file is part of company 0.5.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index d388e3e..d22dfd5 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.4.3
+;; Version: 0.5
 ;; Keywords: abbrev, convenience, matching
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2010-02-24 (0.5)
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
 ;;    Added `company-with-candidate-inserted' macro.
 ;;    Added `company-clang' back-end.

commit 5ffa21480181cbff600a90f2cf75803b9a92a006
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 21:57:50 2010 +0100

    Bumped copyright years.

diff --git a/company-eclim.el b/company-eclim.el
index a9312f8..97487fc 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,6 +1,6 @@
 ;;; company-eclim.el --- a company-mode completion back-end for eclim.
 ;;
-;; Copyright (C) 2009 Nikolaj Schumacher
+;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; This file is part of company 0.4.3.
 ;;
diff --git a/company-etags.el b/company-etags.el
index 75b07a0..95608a9 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -1,6 +1,6 @@
 ;;; company-etags.el --- a company-mode completion back-end for etags
 ;;
-;; Copyright (C) 2009 Nikolaj Schumacher
+;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; This file is part of company 0.4.3.
 ;;
diff --git a/company-ropemacs.el b/company-ropemacs.el
index bbd3b63..b5c97cd 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,6 +1,6 @@
 ;;; company-ropemacs.el --- a company-mode completion back-end for pysmell.el
 ;;
-;; Copyright (C) 2009 Nikolaj Schumacher
+;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; This file is part of company 0.4.3.
 ;;
diff --git a/company-semantic.el b/company-semantic.el
index 263bbaa..e6e4c56 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,6 +1,6 @@
 ;;; company-semantic.el --- a company-mode back-end using CEDET Semantic
 ;;
-;; Copyright (C) 2009 Nikolaj Schumacher
+;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; This file is part of company 0.4.3.
 ;;
diff --git a/company.el b/company.el
index 228b3c2..d388e3e 100644
--- a/company.el
+++ b/company.el
@@ -1,6 +1,6 @@
 ;;; company.el --- extensible inline text completion mechanism
 ;;
-;; Copyright (C) 2009 Nikolaj Schumacher
+;; Copyright (C) 2009-2010 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
 ;; Version: 0.4.3

commit 33802e0c65c1e3755f98c463bd2ec89c6bc322cf
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Feb 23 22:42:48 2010 +0100

    Replaced call to removed semantic-ia-get-completions.

diff --git a/company-semantic.el b/company-semantic.el
index 277e4ec..263bbaa 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -18,8 +18,8 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(or (require 'semantic-ia nil t)
-    (require 'semantic/ia))
+(or (require 'semantic-analyze nil t)
+    (require 'semantic/analyze))
 (eval-when-compile (require 'cl))
 
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
@@ -34,7 +34,9 @@
 
 (defun company-semantic-doc-or-summary (tag)
   (or (semantic-documentation-for-tag tag)
-      (funcall semantic-idle-summary-function tag nil t)))
+      (and (require 'semantic-idle nil t)
+           (require 'semantic/idle nil t)
+           (funcall semantic-idle-summary-function tag nil t))))
 
 (defun company-semantic-summary-and-doc (tag)
   (let ((doc (semantic-documentation-for-tag tag))
@@ -63,7 +65,7 @@
     (let ((completion-ignore-case nil)
           (context (semantic-analyze-current-context)))
       (setq company-semantic--current-tags
-            (semantic-ia-get-completions context (point)))
+            (semantic-analyze-possible-completions context))
       (all-completions prefix company-semantic--current-tags))))
 
 (defun company-semantic-completions-raw (prefix)
diff --git a/company.el b/company.el
index b10f9c1..228b3c2 100644
--- a/company.el
+++ b/company.el
@@ -71,7 +71,7 @@
 ;;    Added new mechanism for non-consecutive insertion.
 ;;      (So far only used by clang for ObjC.)
 ;;    The semantic back-end now shows meta information for local symbols.
-;;    Added compatibility for CEDET in Emacs 23.2.
+;;    Added compatibility for CEDET in Emacs 23.2 and from CVS.  (Oleg Andreev)
 ;;
 ;; 2009-05-07 (0.4.3)
 ;;    Added `company-other-backend'.

commit e19a153219a3d192fb78266e13916cf0c04c03e9
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 22:05:45 2010 +0100

    Changed default for company-eclim-auto-save.

diff --git a/company-eclim.el b/company-eclim.el
index 16fc7cb..a9312f8 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -35,7 +35,7 @@
   :group 'company
   :type 'file)
 
-(defcustom company-eclim-auto-save nil
+(defcustom company-eclim-auto-save t
   "*Determines whether to save the buffer when retrieving completions.
 eclim can only complete correctly when the buffer has been saved."
   :group 'company

commit 7829277217f388316dd7477cfc680a8a2e3b2e6a
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 22:04:43 2010 +0100

    Fixed wrong file keyword.

diff --git a/company.el b/company.el
index bc296be..b10f9c1 100644
--- a/company.el
+++ b/company.el
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
 ;; Version: 0.4.3
-;; Keywords: abbrev, convenience, matchis
+;; Keywords: abbrev, convenience, matching
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
 ;;
@@ -148,7 +148,7 @@
   "Extensible inline text completion mechanism"
   :group 'abbrev
   :group 'convenience
-  :group 'maching)
+  :group 'matching)
 
 (defface company-tooltip
   '((t :background "yellow"

commit d95de5f29b7ce8648854a00a5cb4dd6b7bbd5514
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Feb 20 00:20:55 2010 +0100

    Added template insertion for ObjC selectors.

diff --git a/company-clang.el b/company-clang.el
index 2cb2ce8..c38a043 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -176,6 +176,19 @@ Prefix files (-include ...) can be selected with
     (when (re-search-forward "\\`clang version \\([0-9.]+\\)" nil t)
       (match-string-no-properties 1))))
 
+(defun company-clang-objc-templatify (selector)
+  (let* ((end (point))
+         (beg (- (point) (length selector)))
+         (templ (company-template-declare-template beg end)))
+    (save-excursion
+      (goto-char beg)
+      (while (search-forward ":" end t)
+        (replace-match ":  ")
+        (incf end 2)
+        (company-template-add-field templ (1- (match-end 0)) "<arg>"))
+      (delete-char -1))
+    (company-template-move-to-first templ)))
+
 (defun company-clang (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for clang.
 Clang is a parser for C and ObjC.  The unreleased development version of
@@ -201,7 +214,10 @@ Completions only work correctly when the buffer has been 
saved.
                       company-clang-executable
                       (not (company-in-string-or-comment))
                       (or (company-grab-symbol) 'stop)))
-        ('candidates (company-clang--candidates arg))))
+        ('candidates (company-clang--candidates arg))
+        ('post-completion (and (derived-mode-p 'objc-mode)
+                               (string-match ":" arg)
+                               (company-clang-objc-templatify arg)))))
 
 (provide 'company-clang)
 ;;; company-clang.el ends here
diff --git a/company-template.el b/company-template.el
new file mode 100644
index 0000000..f9b0fcd
--- /dev/null
+++ b/company-template.el
@@ -0,0 +1,114 @@
+(eval-when-compile (require 'cl))
+
+(defface company-template-field
+  '((((background dark)) (:background "yellow" :foreground "black"))
+    (((background light)) (:background "orange" :foreground "black")))
+  "*Face used for editable text in template fields."
+  :group 'company)
+
+(defvar company-template-nav-map
+  (let ((keymap (make-sparse-keymap)))
+    (define-key keymap [remap forward-word] 'company-template-forward-field)
+    (define-key keymap [remap subword-forward] 'company-template-forward-field)
+    ;; M-n
+    keymap))
+
+;; interactive 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defsubst company-template-templates-at (pos)
+  (let (os)
+    (dolist (o (overlays-at pos))
+      (when (overlay-get o 'company-template-fields)
+        (push o os)))
+    os))
+
+(defun company-template-move-to-first (templ)
+  (interactive)
+  (let ((fields (overlay-get templ 'company-template-fields)))
+    (push-mark)
+    (goto-char (apply 'min (mapcar 'overlay-start fields)))))
+
+(defun company-template-forward-field ()
+  (interactive)
+  (let* ((templates (company-template-templates-at (point)))
+         (minimum (apply 'max (mapcar 'overlay-end templates)))
+         (fields (apply 'append
+                        (mapcar (lambda (templ)
+                                  (overlay-get templ 'company-template-fields))
+                                templates))))
+    (dolist (pos (mapcar 'overlay-start fields))
+      (and pos
+           (> pos (point))
+           (< pos minimum)
+           (setq minimum pos)))
+    (push-mark)
+    (goto-char minimum)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-template--buffer-templates nil)
+(make-variable-buffer-local 'company-template--buffer-templates)
+
+(defun company-template-declare-template (beg end)
+  (let ((ov (make-overlay beg end)))
+    ;; (overlay-put ov 'face 'highlight)
+    (overlay-put ov 'keymap company-template-nav-map)
+    (overlay-put ov 'evaporate t)
+    (push ov company-template--buffer-templates)
+    (add-hook 'post-command-hook 'company-template-post-command nil t)
+    ov))
+
+(defun company-template-remove-template (templ)
+  (mapc 'company-template-remove-field
+        (overlay-get templ 'company-template-fields))
+  (setq company-template--buffer-templates
+        (delq templ company-template--buffer-templates))
+  (delete-overlay templ))
+
+(defun company-template-add-field (templ pos text)
+  (assert templ)
+  (save-excursion
+    ;; (goto-char pos)
+    (let ((ov (make-overlay pos pos))
+          (siblings (overlay-get templ 'company-template-fields))
+          (label (propertize text 'face 'company-template-field
+                             'company-template-parent templ)))
+      (overlay-put ov 'face 'highlight)
+      (add-text-properties 0 1 '(cursor t) label)
+      (overlay-put ov 'after-string label)
+      ;; (overlay-put ov 'evaporate t)
+      (overlay-put ov 'intangible t)
+      (overlay-put ov 'company-template-parent templ)
+      (overlay-put ov 'insert-in-front-hooks '(company-template-remove))
+      (push ov siblings)
+      (overlay-put templ 'company-template-fields siblings))))
+
+(defun company-template-remove-field (field)
+  (when (overlayp field)
+    ;; (delete-region (overlay-start field) (overlay-end field))
+    (delete-overlay field))
+  ;; TODO: unlink
+  )
+
+(defun company-template-clean-up (&optional pos)
+  "Clean up all templates that don't contain POS."
+  (unless pos (setq pos (point)))
+  (let ((local-ovs (overlays-in (- pos 2) pos)))
+    (dolist (templ company-template--buffer-templates)
+      (unless (memq templ local-ovs)
+        (company-template-remove-template templ)))))
+
+;; hooks 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-template-remove (overlay after-p beg end &optional r)
+  "Called when a snippet input prompt is modified."
+  (when after-p
+    (delete-overlay overlay)))
+
+(defun company-template-post-command ()
+  (company-template-clean-up)
+  (unless company-template--buffer-templates
+    (remove-hook 'post-command-hook 'company-template-post-command t)))
+
+(provide 'company-template)
+;;; company-template.el ends here
diff --git a/company.el b/company.el
index eddd4cb..bc296be 100644
--- a/company.el
+++ b/company.el
@@ -68,6 +68,8 @@
 ;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
 ;;    Added `company-with-candidate-inserted' macro.
 ;;    Added `company-clang' back-end.
+;;    Added new mechanism for non-consecutive insertion.
+;;      (So far only used by clang for ObjC.)
 ;;    The semantic back-end now shows meta information for local symbols.
 ;;    Added compatibility for CEDET in Emacs 23.2.
 ;;
@@ -1978,5 +1980,9 @@ Returns a negative number if the tooltip should be 
displayed above point."
     ('post-command (company-echo-show-soon 'company-fetch-metadata))
     ('hide (company-echo-hide))))
 
+;; templates 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(autoload 'company-template-declare-template "company-template")
+
 (provide 'company)
 ;;; company.el ends here

commit b4000375741909e713cd37bff35ac3380e8cece5
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jan 9 20:01:32 2010 +0100

    Added 'pre-completion and 'post-completion back-end commands.

diff --git a/company.el b/company.el
index 8bdba31..eddd4cb 100644
--- a/company.el
+++ b/company.el
@@ -1055,7 +1055,10 @@ can retrieve meta-data for them."
        (set-buffer-modified-p nil))
   (when company-prefix
     (if (stringp result)
-        (run-hook-with-args 'company-completion-finished-hook result)
+        (progn
+          (company-call-backend 'pre-completion result)
+          (run-hook-with-args 'company-completion-finished-hook result)
+          (company-call-backend 'post-completion result))
       (run-hook-with-args 'company-completion-cancelled-hook result)))
   (setq company-added-newline nil
         company-backend nil

commit 4e9b543ca711980309b41659631821bca02fa6f2
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 21:50:52 2010 +0100

    Don't use goto-line.

diff --git a/company.el b/company.el
index f654039..8bdba31 100644
--- a/company.el
+++ b/company.el
@@ -1466,9 +1466,12 @@ To show the number next to the candidates in some 
back-ends, enable
            (buffer (or (and (bufferp (car location)) (car location))
                        (find-file-noselect (car location) t))))
       (with-selected-window (display-buffer buffer t)
-        (if (bufferp (car location))
-            (goto-char pos)
-          (goto-line pos))
+        (save-restriction
+          (widen)
+          (if (bufferp (car location))
+              (goto-char pos)
+            (goto-char (point-min))
+            (forward-line (1- pos))))
         (set-window-start nil (point))))))
 (put 'company-show-location 'company-keep t)
 

commit 9fda0594403d6fded1e4d5b62c85204f10da6927
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 15:23:29 2010 +0100

    Move to top of long documentation buffers.

diff --git a/company.el b/company.el
index 37cd893..f654039 100644
--- a/company.el
+++ b/company.el
@@ -1448,9 +1448,12 @@ To show the number next to the candidates in some 
back-ends, enable
   "Temporarily show a buffer with the complete documentation for the 
selection."
   (interactive)
   (company--electric-do
-    (let ((selected (nth company-selection company-candidates)))
-      (display-buffer (or (company-call-backend 'doc-buffer selected)
-                          (error "No documentation available")) t))))
+    (let* ((selected (nth company-selection company-candidates))
+           (doc-buffer (or (company-call-backend 'doc-buffer selected)
+                           (error "No documentation available"))))
+      (with-current-buffer doc-buffer
+        (goto-char (point-min)))
+      (display-buffer doc-buffer t))))
 (put 'company-show-doc-buffer 'company-keep t)
 
 (defun company-show-location ()

commit 71432108563f4033b527818687b7c8484f4af882
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 15:16:02 2010 +0100

    Added 'location and 'doc-buffer commands to ropemacs back-end.

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 371aaa9..bbd3b63 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -38,6 +38,21 @@
                   (skip-syntax-backward "w_"))
                 (- pos (point))))))))
 
+(defun company-ropemacs-doc-buffer (candidate)
+  "Return buffer with docstring of CANDIDATE if it is available."
+  (let ((doc (company-with-candidate-inserted candidate (rope-get-doc))))
+    (when doc
+      (with-current-buffer (company-doc-buffer)
+        (insert doc)
+        (current-buffer)))))
+
+(defun company-ropemacs-location (candidate)
+  "Return location of CANDIDATE in cons form (FILE . LINE) if it is available."
+  (let ((location (company-with-candidate-inserted candidate
+                    (rope-definition-location))))
+    (when location
+      (cons (elt location 0) (elt location 1)))))
+
 (defun company-ropemacs (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for ropemacs."
   (interactive (list 'interactive))
@@ -47,7 +62,9 @@
                   (not (company-in-string-or-comment))
                   (company-ropemacs--grab-symbol)))
     ('candidates (mapcar (lambda (element) (concat arg element))
-                         (rope-completions)))))
+                         (rope-completions)))
+    ('doc-buffer (company-ropemacs-doc-buffer arg))
+    ('location (company-ropemacs-location arg))))
 
 (provide 'company-ropemacs)
 ;;; company-ropemacs.el ends here
diff --git a/company.el b/company.el
index b47ed3e..37cd893 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    `company-ropemacs' now provides location and docs.  (Fernando H. Silva)
 ;;    Added `company-with-candidate-inserted' macro.
 ;;    Added `company-clang' back-end.
 ;;    The semantic back-end now shows meta information for local symbols.

commit 3c7511caf544ae09f484aaf8d531ca8007db56e3
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 15:12:42 2010 +0100

    Added company-with-candidate-inserted macro.

diff --git a/company.el b/company.el
index aaa9c1e..b47ed3e 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-with-candidate-inserted' macro.
 ;;    Added `company-clang' back-end.
 ;;    The semantic back-end now shows meta information for local symbols.
 ;;    Added compatibility for CEDET in Emacs 23.2.
@@ -747,6 +748,19 @@ keymap during active completions (`company-active-map'):
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
+(defmacro company-with-candidate-inserted (candidate &rest body)
+  "Evaluate BODY with CANDIDATE temporarily inserted.
+This is a tool for back-ends that need candidates inserted before they
+can retrieve meta-data for them."
+  (declare (indent 1))
+  `(let ((inhibit-modification-hooks t)
+         (inhibit-point-motion-hooks t)
+         (modified-p (buffer-modified-p)))
+     (insert (company-strip-prefix ,candidate))
+     (unwind-protect
+         (progn ,@body)
+       (delete-region company-point (point)))))
+
 (defun company-explicit-action-p ()
   "Return whether explicit completion action was taken by the user."
   (or company--explicit-action
@@ -1407,19 +1421,24 @@ To show the number next to the candidates in some 
back-ends, enable
     (erase-buffer)
     (current-buffer)))
 
+(defvar company--electric-commands
+  '(scroll-other-window scroll-other-window-down)
+  "List of Commands that won't break out of electric commands.")
+
 (defmacro company--electric-do (&rest body)
   (declare (indent 0) (debug t))
   `(when (company-manual-begin)
      (save-window-excursion
        (let ((height (window-height))
-             (row (company--row)))
+             (row (company--row))
+             cmd)
          ,@body
          (and (< (window-height) height)
               (< (- (window-height) row 2) company-tooltip-limit)
               (recenter (- (window-height) row 2)))
-         (while (eq 'scroll-other-window
-                    (key-binding (vector (list (read-event)))))
-           (call-interactively 'scroll-other-window))
+         (while (memq (setq cmd (key-binding (vector (list (read-event)))))
+                      company--electric-commands)
+           (call-interactively cmd))
          (when last-input-event
            (clear-this-command-keys t)
            (setq unread-command-events (list last-input-event)))))))

commit d82b9260fb1deb5406ae7c0a3465195804ae662a
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Feb 22 00:00:01 2010 +0100

    Prevent point movement caused by 'location in company-etags.

diff --git a/company-etags.el b/company-etags.el
index 51628ef..75b07a0 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -67,8 +67,9 @@ buffer automatically."
                         (all-completions arg (tags-completion-table)))))
     ('location (let ((tags-table-list (company-etags-buffer-table)))
                  (when (fboundp 'find-tag-noselect)
-                   (let ((buffer (find-tag-noselect arg)))
-                     (cons buffer (with-current-buffer buffer (point)))))))
+                   (save-excursion
+                     (let ((buffer (find-tag-noselect arg)))
+                       (cons buffer (with-current-buffer buffer (point))))))))
     ('sorted t)))
 
 (provide 'company-etags)

commit df2d1b1a9d09a8bee968921d05559cb1a12b273c
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Feb 21 23:34:52 2010 +0100

    Fixed header in company-ropemacs.el.

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 7e8bfb5..371aaa9 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -1,4 +1,4 @@
-;;; company-pysmell.el --- a company-mode completion back-end for pysmell.el
+;;; company-ropemacs.el --- a company-mode completion back-end for pysmell.el
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;

commit db36e6d380b7d85a751a0d2c15646c325cc9f1b1
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Feb 21 22:55:07 2010 +0100

    Give some feedback when no completion was found.

diff --git a/company.el b/company.el
index 9488d9e..aaa9c1e 100644
--- a/company.el
+++ b/company.el
@@ -1005,7 +1005,9 @@ keymap during active completions (`company-active-map'):
                 company-backend backend
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
-          (when (consp c)
+          (if (not (consp c))
+              (when company--explicit-action
+                (message "No completion found"))
             (setq company-prefix prefix)
             (when (symbolp backend)
               (setq company-lighter (concat " " (symbol-name backend))))

commit 7d7a8d01a95f2481365ce7068891b9291871d1a1
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Feb 19 18:10:28 2010 +0100

    Check clang version.

diff --git a/company-clang.el b/company-clang.el
index 24f79b0..2cb2ce8 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -164,6 +164,18 @@ Prefix files (-include ...) can be selected with
          prefix
          (company-clang--build-complete-args (- (point) (length prefix)))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst company-clang-required-version "1.1")
+
+(defsubst company-clang-version ()
+  "Return the version of `company-clang-executable'."
+  (with-temp-buffer
+    (call-process company-clang-executable nil t nil "--version")
+    (goto-char (point-min))
+    (when (re-search-forward "\\`clang version \\([0-9.]+\\)" nil t)
+      (match-string-no-properties 1))))
+
 (defun company-clang (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for clang.
 Clang is a parser for C and ObjC.  The unreleased development version of
@@ -179,6 +191,11 @@ Completions only work correctly when the buffer has been 
saved.
   (interactive (list 'interactive))
   (case command
         ('interactive (company-begin-backend 'company-clang))
+        ('init (unless company-clang-executable
+                 (error "Company found no clang executable"))
+               (when (version< (company-clang-version)
+                               company-clang-required-version)
+                 (error "Company requires clang version 1.1")))
         ('prefix (and (memq major-mode company-clang-modes)
                       buffer-file-name
                       company-clang-executable

commit 2f98c2ca6d4b960a240ab609b608a5d816eeb23d
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Feb 21 23:01:21 2010 +0100

    Be less verbose when writing files.

diff --git a/company-clang.el b/company-clang.el
index 88f0f6f..24f79b0 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -156,7 +156,7 @@ Prefix files (-include ...) can be selected with
 (defun company-clang--candidates (prefix)
   (and company-clang-auto-save
        (buffer-modified-p)
-       (save-buffer))
+       (basic-save-buffer))
   (when (null company-clang--prefix)
     (company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
                                   'none)))
diff --git a/company-eclim.el b/company-eclim.el
index 0441b5c..16fc7cb 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -98,7 +98,7 @@ eclim can only complete correctly when the buffer has been 
saved."
         (project-name (company-eclim--project-name)))
     (when company-eclim-auto-save
       (when (buffer-modified-p)
-        (save-buffer))
+        (basic-save-buffer))
       ;; FIXME: Sometimes this isn't finished when we complete.
       (company-eclim--call-process "java_src_update"
                                   "-p" (company-eclim--project-name)

commit bef5252724d2da5345c18a3107606103cb011f90
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Feb 21 19:48:10 2010 +0100

    Don't auto-save buffers when they haven't been modified.

diff --git a/company-clang.el b/company-clang.el
index 855dc94..88f0f6f 100644
--- a/company-clang.el
+++ b/company-clang.el
@@ -154,8 +154,9 @@ Prefix files (-include ...) can be selected with
           (list buffer-file-name)))
 
 (defun company-clang--candidates (prefix)
-  (when company-clang-auto-save
-    (save-buffer))
+  (and company-clang-auto-save
+       (buffer-modified-p)
+       (save-buffer))
   (when (null company-clang--prefix)
     (company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
                                   'none)))
diff --git a/company-eclim.el b/company-eclim.el
index 9f5c507..0441b5c 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -97,7 +97,8 @@ eclim can only complete correctly when the buffer has been 
saved."
                                           (company-eclim--project-dir)))
         (project-name (company-eclim--project-name)))
     (when company-eclim-auto-save
-      (save-buffer)
+      (when (buffer-modified-p)
+        (save-buffer))
       ;; FIXME: Sometimes this isn't finished when we complete.
       (company-eclim--call-process "java_src_update"
                                   "-p" (company-eclim--project-name)

commit cb7d8ada99f5b24f9961cef5bbd8f2f3250652b7
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Feb 19 12:07:49 2010 +0100

    Added back-end for clang.

diff --git a/company-clang.el b/company-clang.el
new file mode 100644
index 0000000..855dc94
--- /dev/null
+++ b/company-clang.el
@@ -0,0 +1,189 @@
+;;; company-clang.el --- a company-mode completion back-end for clang
+;;
+;; Copyright (C) 2010 Nikolaj Schumacher
+;;
+;; This file is part of company 0.4.3.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defcustom company-clang-executable
+  (executable-find "clang")
+  "*Location of clang executable"
+  :group 'company-clang
+  :type 'file)
+
+(defcustom company-clang-auto-save t
+  "*Determines whether to save the buffer when retrieving completions.
+clang can only complete correctly when the buffer has been saved."
+  :group 'company-clang
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" t)))
+
+(defcustom company-clang-arguments nil
+  "*Additional arguments to pass to clang when completing.
+Prefix files (-include ...) can be selected with
+`company-clang-set-prefix' or automatically through a custom
+`company-clang-prefix-guesser'."
+  :group 'company-clang
+  :type '(repeat (string :tag "Argument" nil)))
+
+(defcustom company-clang-prefix-guesser 'company-clang-guess-prefix
+  "*A function to determine the prefix file for the current buffer."
+  :group 'company-clang
+  :type '(function :tag "Guesser function" nil))
+
+(defvar company-clang-modes '(c-mode objc-mode)
+  "Major modes which clang may complete.")
+
+;; prefix 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-clang--prefix nil)
+
+(defsubst company-clang--guess-pch-file (file)
+  (let ((dir (directory-file-name (file-name-directory file))))
+    (when (equal (file-name-nondirectory dir) "Classes")
+      (setq dir (file-name-directory dir)))
+    (car (directory-files dir t "\\([^.]h\\|[^h]\\).pch\\'" t))))
+
+(defsubst company-clang--file-substring (file beg end)
+  (with-temp-buffer
+    (insert-file-contents-literally file nil beg end)
+    (buffer-string)))
+
+(defun company-clang-guess-prefix ()
+  "Try to guess the prefix file for the current buffer."
+  ;; Prefixes seem to be called .pch.  Pre-compiled headers do, too.
+  ;; So we look at the magic number to rule them out.
+  (let* ((file (company-clang--guess-pch-file buffer-file-name))
+         (magic-number (company-clang--file-substring file 0 4)))
+    (unless (member magic-number '("CPCH" "gpch"))
+      file)))
+
+(defun company-clang-set-prefix (&optional prefix)
+  "Use PREFIX as a prefix (-include ...) file for clang completion."
+  (interactive (let ((def (funcall company-clang-prefix-guesser)))
+     (unless (stringp def)
+       (setq def default-directory))
+     (list (read-file-name "Prefix file: "
+                           (when def (file-name-directory def))
+                           def t (when def (file-name-nondirectory def))))))
+  ;; TODO: pre-compile?
+  (setq company-clang--prefix (and (stringp prefix)
+                                   (file-regular-p prefix)
+                                   prefix)))
+
+;; Clean-up on exit.
+(add-hook 'kill-emacs-hook 'company-clang-set-prefix)
+
+;; parsing 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: How to handle OVERLOAD and Pattern?
+(defconst company-clang--completion-pattern
+  "^COMPLETION: \\_<\\(%s[a-zA-Z0-9_:]*\\)")
+
+(defconst company-clang--error-buffer-name "*clang error*")
+
+(defun company-clang--parse-output (prefix)
+  (goto-char (point-min))
+  (let ((pattern (format company-clang--completion-pattern
+                         (regexp-quote prefix)))
+        lines match)
+    (while (re-search-forward pattern nil t)
+      (setq match (match-string-no-properties 1))
+      (unless (equal match "Pattern")
+        (push match lines)))
+    lines))
+
+(defun company-clang--handle-error (res args)
+  (goto-char (point-min))
+  (let* ((buf (get-buffer-create company-clang--error-buffer-name))
+         (cmd (concat company-clang-executable (mapconcat 'identity args " ")))
+         (pattern (format company-clang--completion-pattern ""))
+         (err (if (re-search-forward pattern nil t)
+                  (buffer-substring-no-properties (point-min)
+                                                  (1- (match-beginning 0)))
+                ;; Warn the user more agressively if no match was found.
+                (message "clang failed with error %d:\n%s" res cmd)
+                (buffer-string))))
+
+    (with-current-buffer buf
+      (let ((inhibit-read-only t))
+        (erase-buffer)
+        (insert (current-time-string)
+                (format "\nclang failed with error %d:\n" res)
+                cmd "\n\n")
+        (insert err)
+        (setq buffer-read-only t)
+        (goto-char (point-min))))))
+
+(defun company-clang--call-process (prefix &rest args)
+  (with-temp-buffer
+    (let ((res (apply 'call-process company-clang-executable nil t nil args)))
+      (unless (eq 0 res)
+        (company-clang--handle-error res args))
+      ;; Still try to get any useful input.
+      (company-clang--parse-output prefix))))
+
+(defsubst company-clang--build-location (pos)
+  (save-excursion
+    (goto-char pos)
+    (format "%s:%d:%d" buffer-file-name (line-number-at-pos)
+            (1+ (current-column)))))
+
+(defsubst company-clang--build-complete-args (pos)
+  (append '("-cc1" "-fsyntax-only")
+          company-clang-arguments
+          (when (stringp company-clang--prefix)
+            (list "-include" (expand-file-name company-clang--prefix)))
+          '("-code-completion-at")
+          (list (company-clang--build-location pos))
+          (list buffer-file-name)))
+
+(defun company-clang--candidates (prefix)
+  (when company-clang-auto-save
+    (save-buffer))
+  (when (null company-clang--prefix)
+    (company-clang-set-prefix (or (funcall company-clang-prefix-guesser)
+                                  'none)))
+  (apply 'company-clang--call-process
+         prefix
+         (company-clang--build-complete-args (- (point) (length prefix)))))
+
+(defun company-clang (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for clang.
+Clang is a parser for C and ObjC.  The unreleased development version of
+clang (1.1) is required.
+
+Additional command line arguments can be specified in
+`company-clang-arguments'.  Prefix files (-include ...) can be selected
+with `company-clang-set-prefix' or automatically through a custom
+`company-clang-prefix-guesser'.
+
+Completions only work correctly when the buffer has been saved.
+`company-clang-auto-save' determines whether to do this automatically."
+  (interactive (list 'interactive))
+  (case command
+        ('interactive (company-begin-backend 'company-clang))
+        ('prefix (and (memq major-mode company-clang-modes)
+                      buffer-file-name
+                      company-clang-executable
+                      (not (company-in-string-or-comment))
+                      (or (company-grab-symbol) 'stop)))
+        ('candidates (company-clang--candidates arg))))
+
+(provide 'company-clang)
+;;; company-clang.el ends here
diff --git a/company.el b/company.el
index b15feae..9488d9e 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-clang' back-end.
 ;;    The semantic back-end now shows meta information for local symbols.
 ;;    Added compatibility for CEDET in Emacs 23.2.
 ;;
@@ -273,6 +274,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
 
 (defvar company-safe-backends
   '((company-abbrev . "Abbrev")
+    (company-clang . "clang")
     (company-css . "CSS")
     (company-dabbrev . "dabbrev for plain text")
     (company-dabbrev-code . "dabbrev for code")
@@ -301,8 +303,8 @@ If this many lines are not available, prefer to display the 
tooltip above."
                 (return t))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-eclim company-semantic company-xcode
-                              company-ropemacs
+                              company-eclim company-semantic company-clang
+                              company-xcode company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
                                company-pysmell company-keywords)
                               company-oddmuse company-files company-dabbrev)
@@ -525,14 +527,17 @@ The work-around consists of adding a newline.")
 
   (if (or (symbolp backend)
           (functionp backend))
-      (if (ignore-errors (funcall backend 'init) t)
-          (put backend 'company-init t)
-        (put backend 'company-init 'failed)
-        (unless (memq backend company--disabled-backends)
-          (message "Company back-end '%s' could not be initialized"
-                   backend)
-          (push backend company--disabled-backends))
-        nil)
+      (condition-case err
+          (progn
+            (funcall backend 'init)
+            (put backend 'company-init t))
+        (error
+         (put backend 'company-init 'failed)
+         (unless (memq backend company--disabled-backends)
+           (message "Company back-end '%s' could not be initialized:\n%s"
+                    backend (error-message-string err)))
+         (push backend company--disabled-backends)
+         nil))
     (mapc 'company-init-backend backend)))
 
 (defvar company-default-lighter " company")

commit 9edefd96a4d61dc4bd6e2bf470e785cb2e34828d
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Jan 8 21:33:18 2010 +0100

    Fixed wrong function call in company-ropemacs.

diff --git a/company-ropemacs.el b/company-ropemacs.el
index 1ebac60..7e8bfb5 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -45,7 +45,7 @@
     ('interactive (company-begin-backend 'company-ropemacs))
     ('prefix (and (derived-mode-p 'python-mode)
                   (not (company-in-string-or-comment))
-                  (company-pysmell--grab-symbol)))
+                  (company-ropemacs--grab-symbol)))
     ('candidates (mapcar (lambda (element) (concat arg element))
                          (rope-completions)))))
 

commit bc95274af418b3a64353b2cb2578cdec43d204e8
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Jan 8 00:45:16 2010 +0100

    Changed default value for company-echo-delay.

diff --git a/company.el b/company.el
index 81ecb6c..b15feae 100644
--- a/company.el
+++ b/company.el
@@ -1843,7 +1843,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
 
 (defvar company-echo-timer nil)
 
-(defvar company-echo-delay .1)
+(defvar company-echo-delay .01)
 
 (defun company-echo-show (&optional getter)
   (when getter

commit b34e7cdc45380c06429d2195396f0512620c79b9
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Jan 7 23:48:35 2010 +0100

    Show meta information for local symbols in semantic.

diff --git a/company-semantic.el b/company-semantic.el
index 3fd7226..277e4ec 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -29,6 +29,9 @@
 
 (defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
 
+(defvar company-semantic--current-tags nil
+  "Tags for the current context")
+
 (defun company-semantic-doc-or-summary (tag)
   (or (semantic-documentation-for-tag tag)
       (funcall semantic-idle-summary-function tag nil t)))
@@ -59,14 +62,16 @@
   (ignore-errors
     (let ((completion-ignore-case nil)
           (context (semantic-analyze-current-context)))
-      (all-completions prefix (semantic-ia-get-completions context (point))))))
+      (setq company-semantic--current-tags
+            (semantic-ia-get-completions context (point)))
+      (all-completions prefix company-semantic--current-tags))))
 
 (defun company-semantic-completions-raw (prefix)
-  (let (candidates)
-    (dolist (tag (semantic-analyze-find-tags-by-prefix prefix))
-      (unless (eq (semantic-tag-class tag) 'include)
-        (push (semantic-tag-name tag) candidates)))
-    (delete "" candidates)))
+  (setq company-semantic--current-tags nil)
+  (dolist (tag (semantic-analyze-find-tags-by-prefix prefix))
+    (unless (eq (semantic-tag-class tag) 'include)
+      (push tag company-semantic--current-tags)))
+  (delete "" (mapcar 'semantic-tag-name company-semantic--current-tags)))
 
 (defun company-semantic--pre-prefix-length (prefix-length)
   "Sum up the length of all chained symbols before POS.
@@ -100,11 +105,12 @@ Symbols are chained by \".\" or \"->\"."
                      (company-semantic-completions-raw arg)
                    (company-semantic-completions arg)))
     ('meta (funcall company-semantic-metadata-function
-                    (semantic-analyze-find-tag arg)))
-    ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))
+                    (assoc arg company-semantic--current-tags)))
+    ('doc-buffer (company-semantic-doc-buffer
+                  (assoc arg company-semantic--current-tags)))
     ;; because "" is an empty context and doesn't return local variables
     ('no-cache (equal arg ""))
-    ('location (let ((tag (semantic-analyze-find-tag arg)))
+    ('location (let ((tag (assoc arg company-semantic--current-tags)))
                  (when (buffer-live-p (semantic-tag-buffer tag))
                    (cons (semantic-tag-buffer tag)
                          (semantic-tag-start tag)))))))
diff --git a/company.el b/company.el
index 0e5b9a8..81ecb6c 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    The semantic back-end now shows meta information for local symbols.
 ;;    Added compatibility for CEDET in Emacs 23.2.
 ;;
 ;; 2009-05-07 (0.4.3)

commit b2c434d62c9c7bcc408ddde51e3532d8b9d74013
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Jan 6 20:04:41 2010 +0100

    Added compatibility for CEDET in Emacs 23.2.

diff --git a/company-semantic.el b/company-semantic.el
index 36a50d7..3fd7226 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -18,7 +18,8 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(require 'semantic-ia)
+(or (require 'semantic-ia nil t)
+    (require 'semantic/ia))
 (eval-when-compile (require 'cl))
 
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
diff --git a/company.el b/company.el
index 714ac30..0e5b9a8 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added compatibility for CEDET in Emacs 23.2.
+;;
 ;; 2009-05-07 (0.4.3)
 ;;    Added `company-other-backend'.
 ;;    Idle completion no longer interrupts multi-key command input.

commit 9c6348ecbc8f5403aafe2b3dfccd678a60f921c0
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Jul 18 10:52:37 2009 +0200

    Enable CSS and nxml back-ends for derived modes.

diff --git a/company-css.el b/company-css.el
index d89fd1a..b2d4c6a 100644
--- a/company-css.el
+++ b/company-css.el
@@ -276,7 +276,7 @@ Returns \"\" if no property found, but feasible at this 
position."
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-css))
-    ('prefix (and (eq major-mode 'css-mode)
+    ('prefix (and (derived-mode-p 'css-mode)
                   (or (company-grab company-css-tag-regexp 1)
                       (company-grab company-css-pseudo-regexp 1)
                       (company-grab company-css-property-value-regexp 2)
diff --git a/company-nxml.el b/company-nxml.el
index 3c4292a..4fc615c 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -60,7 +60,7 @@
 
 (defun company-nxml-tag (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (eq major-mode 'nxml-mode)
+    ('prefix (and (derived-mode-p 'nxml-mode)
                   rng-validate-mode
                   (company-grab company-nxml-in-tag-name-regexp 1)))
     ('candidates (company-nxml-prepared
@@ -70,7 +70,7 @@
 
 (defun company-nxml-attribute (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (eq major-mode 'nxml-mode)
+    ('prefix (and (derived-mode-p 'nxml-mode)
                   rng-validate-mode
                   (memq (char-after) '(?\  ?\t ?\n)) ;; outside word
                   (company-grab rng-in-attribute-regex 1)))
@@ -83,7 +83,7 @@
 
 (defun company-nxml-attribute-value (command &optional arg &rest ignored)
   (case command
-    ('prefix (and (eq major-mode 'nxml-mode)
+    ('prefix (and (derived-mode-p 'nxml-mode)
                   rng-validate-mode
                   (and (memq (char-after) '(?' ?\" ?\  ?\t ?\n)) ;; outside 
word
                        (looking-back company-nxml-in-attribute-value-regexp)

commit 7e6e1b7ba0c797e4692bda59ea500f953d9b7be5
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 14:50:08 2009 +0200

    Bumped version to 0.4.3.

diff --git a/company-abbrev.el b/company-abbrev.el
index 512a9c0..5c807a3 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index 45c59d2..d89fd1a 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 5b6ad4e..e66b8ff 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index ef2e7a0..176a500 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-eclim.el b/company-eclim.el
index d17a186..9f5c507 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index 76c32c6..4c68cbb 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index c6e5347..51628ef 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 069809f..8915876 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 196050d..2d08035 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index ba54ce1..2a153aa 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-keywords.el b/company-keywords.el
index ee6101f..d640932 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 526b670..3c4292a 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 15c0271..85e6bfa 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-pysmell.el b/company-pysmell.el
index f91c275..6fc3574 100644
--- a/company-pysmell.el
+++ b/company-pysmell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ropemacs.el b/company-ropemacs.el
index d32ec77..1ebac60 100644
--- a/company-ropemacs.el
+++ b/company-ropemacs.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index 678a1dd..36a50d7 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index a6098e7..2ce4330 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 8458d4d..1d71a31 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.2.
+;; This file is part of company 0.4.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index 3bd1d5c..714ac30 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.4.2
+;; Version: 0.4.3
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-05-07 (0.4.3)
 ;;    Added `company-other-backend'.
 ;;    Idle completion no longer interrupts multi-key command input.
 ;;    Added `company-ropemacs' and `company-pysmell' back-ends.

commit ff6025edcc99b6344d39004269547a75e1d05e9b
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 14:09:24 2009 +0200

    Added test case to ensure keywords are sorted.

diff --git a/tests.elk b/tests.elk
new file mode 100644
index 0000000..0d9288b
--- /dev/null
+++ b/tests.elk
@@ -0,0 +1,11 @@
+(require 'elk-test)
+
+(deftest "Sorted keywords"
+  (require 'company-keywords)
+  (dolist (pair company-keywords-alist)
+    (when (consp (cdr pair))
+      (let ((prev (cadr pair)))
+        (dolist (next (cddr pair))
+          (assert-not-equal prev next)
+          (assert-string< prev next)
+          (setq prev next))))))

commit 083fd1fe975eecac87f25139fffce88897bc2d44
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 13:46:17 2009 +0200

    Fixed eclim project file matching.

diff --git a/company-eclim.el b/company-eclim.el
index 370444e..d17a186 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -80,7 +80,8 @@ eclim can only complete correctly when the buffer has been 
saved."
   (if (eq company-eclim--project-dir 'unknown)
       (setq company-eclim--project-dir
             (directory-file-name
-             (company-locate-dominating-file buffer-file-name ".project")))
+             (expand-file-name
+              (company-locate-dominating-file buffer-file-name ".project"))))
     company-eclim--project-dir))
 
 (defun company-eclim--project-name ()

commit 3b8f231cc24be0814b3eaea14d2115bafe78f9cd
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 12:53:54 2009 +0200

    Show eclim error message.

diff --git a/company-eclim.el b/company-eclim.el
index 96573e3..370444e 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -62,12 +62,14 @@ eclim can only complete correctly when the buffer has been 
saved."
     lines))
 
 (defun company-eclim--call-process (&rest args)
-  (let ((coding-system-for-read 'utf-8))
+  (let ((coding-system-for-read 'utf-8)
+        res)
     (with-temp-buffer
-      (if (= 0 (apply 'call-process company-eclim-executable nil t nil
-                      "-command" args))
+      (if (= 0 (setq res (apply 'call-process company-eclim-executable nil t 
nil
+                                "-command" args)))
           (company-eclim--buffer-lines)
-        (message "Company-eclim command failed")
+        (message "Company-eclim command failed with error %d:\n%s" res
+                 (buffer-substring (point-min) (point-max)))
         nil))))
 
 (defun company-eclim--project-list ()

commit b59367818eaf4d8c8d16ed5e118385ccbbd89751
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 09:53:46 2009 +0200

    Added company-other-backend.

diff --git a/company.el b/company.el
index 9d3bfe3..3bd1d5c 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-other-backend'.
 ;;    Idle completion no longer interrupts multi-key command input.
 ;;    Added `company-ropemacs' and `company-pysmell' back-ends.
 ;;
@@ -132,6 +133,7 @@
 (add-to-list 'debug-ignored-errors "^Company not ")
 (add-to-list 'debug-ignored-errors "^No candidate number ")
 (add-to-list 'debug-ignored-errors "^Cannot complete at point$")
+(add-to-list 'debug-ignored-errors "^No other back-end$")
 
 (defgroup company nil
   "Extensible inline text completion mechanism"
@@ -305,6 +307,9 @@ Each list elements can itself be a list of back-ends.  In 
that case their
 completions are merged.  Otherwise only the first matching back-end returns
 results.
 
+`company-begin-backend' can be used to start a specific back-end,
+`company-other-backend' will skip to the next matching back-end in the list.
+
 Each back-end is a function that takes a variable number of arguments.
 The first argument is the command requested from the back-end.  It is one
 of the following:
@@ -865,6 +870,23 @@ keymap during active completions (`company-active-map'):
   (setq company--explicit-action t)
   (company-auto-begin))
 
+(defun company-other-backend (&optional backward)
+  (interactive (list current-prefix-arg))
+  (company-assert-enabled)
+  (if company-backend
+      (let* ((after (cdr (member company-backend company-backends)))
+             (before (cdr (member company-backend (reverse company-backends))))
+             (next (if backward
+                       (append before (reverse after))
+                     (append after (reverse before)))))
+        (company-cancel)
+        (dolist (backend next)
+          (when (ignore-errors (company-begin-backend backend))
+            (return t))))
+    (company-manual-begin))
+  (unless company-candidates
+    (error "No other back-end")))
+
 (defun company-require-match-p ()
   (let ((backend-value (company-call-backend 'require-match)))
     (or (eq backend-value t)

commit ba8aaa6a6a30b6ab79d52450bbb431d437c3cf7e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu May 7 09:49:18 2009 +0200

    Don't interrupt multi-key command input by starting idle completion.

diff --git a/company.el b/company.el
index b15022d..9d3bfe3 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Idle completion no longer interrupts multi-key command input.
 ;;    Added `company-ropemacs' and `company-pysmell' back-ends.
 ;;
 ;; 2009-04-25 (0.4.2)
@@ -745,6 +746,9 @@ keymap during active completions (`company-active-map'):
 (defun company--should-complete ()
   (and (not (or buffer-read-only overriding-terminal-local-map
                 overriding-local-map))
+       ;; Check if in the middle of entering a key combination.
+       (or (equal (this-command-keys-vector) [])
+           (not (keymapp (key-binding (this-command-keys-vector)))))
        (eq company-idle-delay t)
        (or (eq t company-begin-commands)
            (memq this-command company-begin-commands)

commit fa431021f2637a6b135a355304ceb6be0cfb58e1
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 17:30:44 2009 +0200

    Don't complete // as file name.

diff --git a/company-files.el b/company-files.el
index bb58d1c..069809f 100644
--- a/company-files.el
+++ b/company-files.el
@@ -41,6 +41,7 @@
            (when (setq file (company-grab-line regexp 1))
              (return file)))
          (setq dir (file-name-directory file))
+         (not (string-match "//" dir))
          (file-exists-p dir)
          (file-name-all-completions (file-name-nondirectory file) dir)
          file)))

commit f7949d1e46904fb58bb3d51b8effa249dd165523
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 17:27:23 2009 +0200

    Added Fortran keywords.

diff --git a/company-keywords.el b/company-keywords.el
index cd1eb07..ee6101f 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -20,9 +20,13 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
+(defun company-keywords-upper-lower (&rest lst)
+  ;; Upcase order is different for _.
+  (nconc (sort (mapcar 'upcase lst) 'string<) lst))
+
 (defvar company-keywords-alist
   ;; Please contribute corrections or additions.
-  '((c++-mode
+  `((c++-mode
      "asm" "auto" "bool" "break" "case" "catch" "char" "class" "const"
      "const_cast" "continue" "default" "delete" "do" "double" "dynamic_cast"
      "else" "enum" "explicit" "export" "extern" "false" "float" "for" "friend"
@@ -63,6 +67,69 @@
      "super" "switch" "synchronized" "template" "this" "throw" "true" "try"
      "typedef" "typeid" "typeof" "ubyte" "ucent" "uint" "ulong" "union"
      "unittest" "ushort" "version" "void" "volatile" "wchar" "while" "with")
+    (f90-mode .
+     ;; from f90.el
+     ;; ".AND." ".GE." ".GT." ".LT." ".LE." ".NE." ".OR." ".TRUE." ".FALSE."
+     ,(company-keywords-upper-lower
+      "abs" "abstract" "achar" "acos" "adjustl" "adjustr" "aimag" "aint"
+      "align" "all" "all_prefix" "all_scatter" "all_suffix" "allocatable"
+      "allocate" "allocated" "and" "anint" "any" "any_prefix" "any_scatter"
+      "any_suffix" "asin" "assign" "assignment" "associate" "associated"
+      "asynchronous" "atan" "atan2" "backspace" "bind" "bit_size" "block"
+      "btest" "c_alert" "c_associated" "c_backspace" "c_bool"
+      "c_carriage_return" "c_char" "c_double" "c_double_complex" "c_f_pointer"
+      "c_f_procpointer" "c_float" "c_float_complex" "c_form_feed" "c_funloc"
+      "c_funptr" "c_horizontal_tab" "c_int" "c_int16_t" "c_int32_t" "c_int64_t"
+      "c_int8_t" "c_int_fast16_t" "c_int_fast32_t" "c_int_fast64_t"
+      "c_int_fast8_t" "c_int_least16_t" "c_int_least32_t" "c_int_least64_t"
+      "c_int_least8_t" "c_intmax_t" "c_intptr_t" "c_loc" "c_long"
+      "c_long_double" "c_long_double_complex" "c_long_long" "c_new_line"
+      "c_null_char" "c_null_funptr" "c_null_ptr" "c_ptr" "c_short"
+      "c_signed_char" "c_size_t" "c_vertical_tab" "call" "case" "ceiling"
+      "char" "character" "character_storage_size" "class" "close" "cmplx"
+      "command_argument_count" "common" "complex" "conjg" "contains" "continue"
+      "copy_prefix" "copy_scatter" "copy_suffix" "cos" "cosh" "count"
+      "count_prefix" "count_scatter" "count_suffix" "cpu_time" "cshift"
+      "cycle" "cyclic" "data" "date_and_time" "dble" "deallocate" "deferred"
+      "digits" "dim" "dimension" "distribute" "do" "dot_product" "double"
+      "dprod" "dynamic" "elemental" "else" "elseif" "elsewhere" "end" "enddo"
+      "endfile" "endif" "entry" "enum" "enumerator" "eoshift" "epsilon" "eq"
+      "equivalence" "eqv" "error_unit" "exit" "exp" "exponent" "extends"
+      "extends_type_of" "external" "extrinsic" "false" "file_storage_size"
+      "final" "floor" "flush" "forall" "format" "fraction" "function" "ge"
+      "generic" "get_command" "get_command_argument" "get_environment_variable"
+      "goto" "grade_down" "grade_up" "gt" "hpf_alignment" "hpf_distribution"
+      "hpf_template" "huge" "iachar" "iall" "iall_prefix" "iall_scatter"
+      "iall_suffix" "iand" "iany" "iany_prefix" "iany_scatter" "iany_suffix"
+      "ibclr" "ibits" "ibset" "ichar" "ieee_arithmetic" "ieee_exceptions"
+      "ieee_features" "ieee_get_underflow_mode" "ieee_set_underflow_mode"
+      "ieee_support_underflow_control" "ieor" "if" "ilen" "implicit"
+      "import" "include" "independent" "index" "inherit" "input_unit"
+      "inquire" "int" "integer" "intent" "interface" "intrinsic" "ior"
+      "iostat_end" "iostat_eor" "iparity" "iparity_prefix" "iparity_scatter"
+      "iparity_suffix" "ishft" "ishftc" "iso_c_binding" "iso_fortran_env"
+      "kind" "lbound" "le" "leadz" "len" "len_trim" "lge" "lgt" "lle" "llt"
+      "log" "log10" "logical" "lt" "matmul" "max" "maxexponent" "maxloc"
+      "maxval" "maxval_prefix" "maxval_scatter" "maxval_suffix" "merge"
+      "min" "minexponent" "minloc" "minval" "minval_prefix" "minval_scatter"
+      "minval_suffix" "mod" "module" "modulo" "move_alloc" "mvbits" "namelist"
+      "ne" "nearest" "neqv" "new" "new_line" "nint" "non_intrinsic"
+      "non_overridable" "none" "nopass" "not" "null" "nullify"
+      "number_of_processors" "numeric_storage_size" "only" "onto" "open"
+      "operator" "optional" "or" "output_unit" "pack" "parameter" "parity"
+      "parity_prefix" "parity_scatter" "parity_suffix" "pass" "pause"
+      "pointer" "popcnt" "poppar" "precision" "present" "print" "private"
+      "procedure" "processors" "processors_shape" "product" "product_prefix"
+      "product_scatter" "product_suffix" "program" "protected" "public"
+      "pure" "radix" "random_number" "random_seed" "range" "read" "real"
+      "realign" "recursive" "redistribute" "repeat" "reshape" "result"
+      "return" "rewind" "rrspacing" "same_type_as" "save" "scale" "scan"
+      "select" "selected_char_kind" "selected_int_kind" "selected_real_kind"
+      "sequence" "set_exponent" "shape" "sign" "sin" "sinh" "size" "spacing"
+      "spread" "sqrt" "stop" "subroutine" "sum" "sum_prefix" "sum_scatter"
+      "sum_suffix" "system_clock" "tan" "tanh" "target" "template" "then"
+      "tiny" "transfer" "transpose" "trim" "true" "type" "ubound" "unpack"
+      "use" "value" "verify" "volatile" "wait" "where" "while" "with" "write"))
     (java-mode
      "abstract" "assert" "boolean" "break" "byte" "case" "catch" "char" "class"
      "continue" "default" "do" "double" "else" "enum" "extends" "final"

commit 23ff7f02c3b589341921395ec8ad1447cc367785
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 16:22:05 2009 +0200

    Added company-ropemacs.

diff --git a/company-ropemacs.el b/company-ropemacs.el
new file mode 100644
index 0000000..d32ec77
--- /dev/null
+++ b/company-ropemacs.el
@@ -0,0 +1,53 @@
+;;; company-pysmell.el --- a company-mode completion back-end for pysmell.el
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.4.2.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(eval-when-compile (require 'cl))
+(require 'pymacs)
+
+(unless (fboundp 'rope-completions)
+  (pymacs-load "ropemacs" "rope-"))
+
+(unless (fboundp 'rope-completions)
+  (error "rope-completions not found, try development version of ropemacs"))
+
+(defun company-ropemacs--grab-symbol ()
+  (let ((symbol (company-grab-symbol)))
+    (when symbol
+      (cons symbol
+            (save-excursion
+              (let ((pos (point)))
+                (goto-char (- (point) (length symbol)))
+                (while (eq (char-before) ?.)
+                  (goto-char (1- (point)))
+                  (skip-syntax-backward "w_"))
+                (- pos (point))))))))
+
+(defun company-ropemacs (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for ropemacs."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-ropemacs))
+    ('prefix (and (derived-mode-p 'python-mode)
+                  (not (company-in-string-or-comment))
+                  (company-pysmell--grab-symbol)))
+    ('candidates (mapcar (lambda (element) (concat arg element))
+                         (rope-completions)))))
+
+(provide 'company-ropemacs)
+;;; company-ropemacs.el ends here
diff --git a/company.el b/company.el
index c71eedb..b15022d 100644
--- a/company.el
+++ b/company.el
@@ -65,7 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
-;;    Added `company-pysmell' back-end.
+;;    Added `company-ropemacs' and `company-pysmell' back-ends.
 ;;
 ;; 2009-04-25 (0.4.2)
 ;;    In C modes . and -> now count towards `company-minimum-prefix-length'.
@@ -279,6 +279,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
     (company-nxml . "nxml")
     (company-oddmuse . "Oddmuse")
     (company-pysmell . "PySmell")
+    (company-ropemacs . "ropemacs")
     (company-semantic . "CEDET Semantic")
     (company-tempo . "Tempo templates")
     (company-xcode . "Xcode")))
@@ -294,6 +295,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
 
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-eclim company-semantic company-xcode
+                              company-ropemacs
                               (company-gtags company-etags company-dabbrev-code
                                company-pysmell company-keywords)
                               company-oddmuse company-files company-dabbrev)

commit 31f7ce2b6153be4fe9257ae911604d7c2e183a7c
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 14:59:36 2009 +0200

    Added company-pysmell.

diff --git a/company-pysmell.el b/company-pysmell.el
new file mode 100644
index 0000000..f91c275
--- /dev/null
+++ b/company-pysmell.el
@@ -0,0 +1,59 @@
+;;; company-pysmell.el --- a company-mode completion back-end for pysmell.el
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.4.2.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(eval-when-compile (require 'cl))
+(require 'pysmell)
+
+(defvar company-pysmell--available-p 'unknown)
+(make-variable-buffer-local 'company-pysmell--available-p)
+
+(defun company-pysmell--available-p ()
+  (if (eq company-pysmell--available-p 'unknown)
+      (setq company-pysmell--available-p
+            (company-locate-dominating-file buffer-file-name "PYSMELLTAGS"))
+    company-pysmell--available-p))
+
+(defun company-pysmell--grab-symbol ()
+  (let ((symbol (company-grab-symbol)))
+    (when symbol
+      (cons symbol
+            (save-excursion
+              (let ((pos (point)))
+                (goto-char (- (point) (length symbol)))
+                (while (eq (char-before) ?.)
+                  (goto-char (1- (point)))
+                  (skip-syntax-backward "w_"))
+                (- pos (point))))))))
+
+;;;###autoload
+(defun company-pysmell (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for pysmell.
+This requires pysmell.el and pymacs.el."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-pysmell))
+    ('prefix (and (derived-mode-p 'python-mode)
+                  buffer-file-name
+                  (not (company-in-string-or-comment))
+                  (company-pysmell--available-p)
+                  (company-pysmell--grab-symbol)))
+    ('candidates (delete "" (pysmell-get-all-completions)))))
+
+(provide 'company-pysmell)
+;;; company-pysmell.el ends here
diff --git a/company.el b/company.el
index c8097e9..c71eedb 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-pysmell' back-end.
+;;
 ;; 2009-04-25 (0.4.2)
 ;;    In C modes . and -> now count towards `company-minimum-prefix-length'.
 ;;    Reverted default front-end back to 
`company-preview-if-just-one-frontend'.
@@ -276,6 +278,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
     (company-keywords . "Programming language keywords")
     (company-nxml . "nxml")
     (company-oddmuse . "Oddmuse")
+    (company-pysmell . "PySmell")
     (company-semantic . "CEDET Semantic")
     (company-tempo . "Tempo templates")
     (company-xcode . "Xcode")))
@@ -292,7 +295,7 @@ If this many lines are not available, prefer to display the 
tooltip above."
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-eclim company-semantic company-xcode
                               (company-gtags company-etags company-dabbrev-code
-                               company-keywords)
+                               company-pysmell company-keywords)
                               company-oddmuse company-files company-dabbrev)
   "*The list of active back-ends (completion engines).
 Each list elements can itself be a list of back-ends.  In that case their

commit c72773c7f45158568754c7d639fcc25f268b7c9a
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 12:43:19 2009 +0200

    Don't start GTAGS, if no GTAGS file was found.

diff --git a/company-gtags.el b/company-gtags.el
index c4d664b..196050d 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -30,8 +30,17 @@
   'company-gtags-gnu-global-program-name
   'company-gtags-executable)
 
+(defvar company-gtags--tags-available-p 'unknown)
+(make-variable-buffer-local 'company-gtags--tags-available-p)
+
 (defvar company-gtags-modes '(c-mode c++-mode jde-mode java-mode php-mode))
 
+(defun company-gtags--tags-available-p ()
+  (if (eq company-gtags--tags-available-p 'unknown)
+      (setq company-gtags--tags-available-p
+            (company-locate-dominating-file buffer-file-name "GTAGS"))
+    company-gtags--tags-available-p))
+
 (defun company-gtags-fetch-tags (prefix)
   (with-temp-buffer
     (let (tags)
@@ -60,6 +69,7 @@
     ('prefix (and company-gtags-executable
                   (memq major-mode company-gtags-modes)
                   (not (company-in-string-or-comment))
+                  (company-gtags--tags-available-p)
                   (or (company-grab-symbol) 'stop)))
     ('candidates (company-gtags-fetch-tags arg))
     ('sorted t)

commit 0d7c69487a7fc00e9648cf622fe2958017353f18
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 12:44:00 2009 +0200

    Removed whitespace.

diff --git a/company-gtags.el b/company-gtags.el
index 61a9163..c4d664b 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -67,5 +67,3 @@
 
 (provide 'company-gtags)
 ;;; company-gtags.el ends here
-
-

commit e43ff95aa19afba4b07c7690f949c5aa45f594d0
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed May 6 12:31:42 2009 +0200

    Don't change lighter to back-end name, if it isn't a symbol.

diff --git a/company.el b/company.el
index edd4797..c8097e9 100644
--- a/company.el
+++ b/company.el
@@ -966,8 +966,9 @@ keymap during active completions (`company-active-map'):
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
           (when (consp c)
-            (setq company-prefix prefix
-                  company-lighter (concat " " (symbol-name backend)))
+            (setq company-prefix prefix)
+            (when (symbolp backend)
+              (setq company-lighter (concat " " (symbol-name backend))))
             (company-update-candidates c)
             (run-hook-with-args 'company-completion-started-hook
                                 (company-explicit-action-p))

commit aa4ec37a77ab65da8058160cfbf83433cab94e04
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 25 09:15:44 2009 +0200

    Bumped version to 0.4.2.

diff --git a/company-abbrev.el b/company-abbrev.el
index 70e93af..512a9c0 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index d08f414..45c59d2 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index a2efcaa..5b6ad4e 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index b80ab3d..ef2e7a0 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-eclim.el b/company-eclim.el
index 4b8a5c9..96573e3 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index c33a07b..76c32c6 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index a5080cd..c6e5347 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 1fc3c5b..bb58d1c 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index d279899..61a9163 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index b6ec708..ba54ce1 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-keywords.el b/company-keywords.el
index ca763b0..cd1eb07 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 7466ada..526b670 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 247a38f..15c0271 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index 13b9133..678a1dd 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index 13c0162..a6098e7 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index df76a57..8458d4d 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.1.
+;; This file is part of company 0.4.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index 1c63460..edd4797 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.4.1
+;; Version: 0.4.2
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-25 (0.4.2)
 ;;    In C modes . and -> now count towards `company-minimum-prefix-length'.
 ;;    Reverted default front-end back to 
`company-preview-if-just-one-frontend'.
 ;;    The pseudo tooltip will no longer be clipped at the right window edge.

commit 072d9f0797b40068aeb99f1c68eaeff72f26a34a
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 25 09:11:33 2009 +0200

    Extracted company-semantic-modes variable.

diff --git a/company-semantic.el b/company-semantic.el
index 25b73f5..13b9133 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -26,6 +26,8 @@
   :group 'company
   :type 'function)
 
+(defvar company-semantic-modes '(c-mode c++-mode jde-mode java-mode))
+
 (defun company-semantic-doc-or-summary (tag)
   (or (semantic-documentation-for-tag tag)
       (funcall semantic-idle-summary-function tag nil t)))
@@ -88,7 +90,7 @@ Symbols are chained by \".\" or \"->\"."
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-semantic))
-    ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
+    ('prefix (and (memq major-mode company-semantic-modes)
                   (semantic-active-p)
                   (not (company-in-string-or-comment))
                   (or (company-semantic--grab) 'stop)))

commit a05b2746f450043afcb8c49bc632425eac1c6974
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 23 19:45:43 2009 +0200

    Parse flet and labels as locally bound values.

diff --git a/company-elisp.el b/company-elisp.el
index 98d335a..c33a07b 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -45,7 +45,7 @@ Functions are offered for completion only after ' and \(."
 
 (defvar company-elisp-binding-regexp
   (concat "([ \t\n]*\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
-                                        "lambda" "lexical-let"))
+                                        "lambda" "lexical-let" "flet" 
"labels"))
           "\\*?")
   "Regular expression matching sexps containing variable bindings.")
 

commit 313de70a8ecc3fabb8692bd353dec86ac9950002
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 23 18:52:34 2009 +0200

    Don't reset company-begin-with-marker if nil.

diff --git a/company.el b/company.el
index 7bbf4e5..1c63460 100644
--- a/company.el
+++ b/company.el
@@ -1417,7 +1417,8 @@ To show the number next to the candidates in some 
back-ends, enable
   (remove-hook 'company-completion-finished-hook company-callback t)
   (remove-hook 'company-completion-cancelled-hook 'company-remove-callback t)
   (remove-hook 'company-completion-finished-hook 'company-remove-callback t)
-  (set-marker company-begin-with-marker nil))
+  (when company-begin-with-marker
+    (set-marker company-begin-with-marker nil)))
 
 (defun company-begin-backend (backend &optional callback)
   "Start a completion at point using BACKEND."

commit 94439c60629cef6aac18f7242fc8303b03ca42ed
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 23 16:19:19 2009 +0200

    Don't use raw candidates list in member contexts.

diff --git a/company-semantic.el b/company-semantic.el
index fbdb1ee..25b73f5 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -92,8 +92,10 @@ Symbols are chained by \".\" or \"->\"."
                   (semantic-active-p)
                   (not (company-in-string-or-comment))
                   (or (company-semantic--grab) 'stop)))
-    ('candidates (or (company-semantic-completions arg)
-                     (company-semantic-completions-raw arg)))
+    ('candidates (if (and (equal arg "")
+                          (not (looking-back "->\\|\\.")))
+                     (company-semantic-completions-raw arg)
+                   (company-semantic-completions arg)))
     ('meta (funcall company-semantic-metadata-function
                     (semantic-analyze-find-tag arg)))
     ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))

commit ef7a28f6232c768b16489b8c7f525b301ad5e2c0
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 23 15:56:27 2009 +0200

    Added missing doc for company-semantic-metadata-function.

diff --git a/company-semantic.el b/company-semantic.el
index 3118e61..fbdb1ee 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -22,7 +22,7 @@
 (eval-when-compile (require 'cl))
 
 (defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
-  "*"
+  "*The function turning a semantic tag into doc information."
   :group 'company
   :type 'function)
 

commit 7aab47898933c308873742a568c3fca14b2a7327
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 22 14:44:55 2009 +0200

    Added option to return separate prefix and prefix length.

diff --git a/company-semantic.el b/company-semantic.el
index ab28541..3118e61 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -65,6 +65,23 @@
         (push (semantic-tag-name tag) candidates)))
     (delete "" candidates)))
 
+(defun company-semantic--pre-prefix-length (prefix-length)
+  "Sum up the length of all chained symbols before POS.
+Symbols are chained by \".\" or \"->\"."
+  (save-excursion
+    (let ((pos (point)))
+      (goto-char (- (point) prefix-length))
+      (while (looking-back "->\\|\\.")
+        (goto-char (match-beginning 0))
+        (skip-syntax-backward "w_"))
+      (- pos (point)))))
+
+(defun company-semantic--grab ()
+  "Grab the semantic prefix, but return everything before -> or . as length."
+  (let ((symbol (company-grab-symbol)))
+    (when symbol
+      (cons symbol (company-semantic--pre-prefix-length (length symbol))))))
+
 ;;;###autoload
 (defun company-semantic (command &optional arg &rest ignored)
   "A `company-mode' completion back-end using CEDET Semantic."
@@ -74,7 +91,7 @@
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
                   (semantic-active-p)
                   (not (company-in-string-or-comment))
-                  (or (company-grab-symbol) 'stop)))
+                  (or (company-semantic--grab) 'stop)))
     ('candidates (or (company-semantic-completions arg)
                      (company-semantic-completions-raw arg)))
     ('meta (funcall company-semantic-metadata-function
diff --git a/company.el b/company.el
index 793af1a..7bbf4e5 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    In C modes . and -> now count towards `company-minimum-prefix-length'.
 ;;    Reverted default front-end back to 
`company-preview-if-just-one-frontend'.
 ;;    The pseudo tooltip will no longer be clipped at the right window edge.
 ;;    Added `company-tooltip-minimum'.
@@ -304,7 +305,10 @@ of the following:
 'prefix: The back-end should return the text to be completed.  It must be
 text immediately before `point'.  Returning nil passes control to the next
 back-end.  The function should return 'stop if it should complete but cannot
-\(e.g. if it is in the middle of a string\).
+\(e.g. if it is in the middle of a string\).  If the returned value is only
+part of the prefix (e.g. the part after \"->\" in C), the back-end may return a
+cons of prefix and prefix length, which is then used in the
+`company-minimum-prefix-length' test.
 
 'candidates: The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.
@@ -910,9 +914,10 @@ keymap during active completions (`company-active-map'):
         nil)))))
 
 (defun company--good-prefix-p (prefix)
-  (and (stringp prefix)
-       (or (company-explicit-action-p)
-           (>= (length prefix) company-minimum-prefix-length))))
+  (and (or (company-explicit-action-p)
+           (>= (or (cdr-safe prefix) (length prefix))
+               company-minimum-prefix-length))
+       (stringp (or (car-safe prefix) prefix))))
 
 (defun company--continue ()
   (when (company-call-backend 'no-cache company-prefix)
@@ -920,8 +925,10 @@ keymap during active completions (`company-active-map'):
     (setq company-candidates-cache nil))
   (let* ((new-prefix (company-call-backend 'prefix))
          (c (when (and (company--good-prefix-p new-prefix)
+                       (setq new-prefix (or (car-safe new-prefix) new-prefix))
                        (= (- (point) (length new-prefix))
                           (- company-point (length company-prefix))))
+              (setq new-prefix (or (car-safe new-prefix) new-prefix))
               (company-calculate-candidates new-prefix))))
     (or (cond
          ((eq c t)
@@ -953,7 +960,8 @@ keymap during active completions (`company-active-map'):
               (company--multi-backend-adapter backend 'prefix)))
       (when prefix
         (when (company--good-prefix-p prefix)
-          (setq company-backend backend
+          (setq prefix (or (car-safe prefix) prefix)
+                company-backend backend
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
           (when (consp c)

commit f5824d8c4ffac2bea9ef5d3c05a60a32279d1603
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 22 14:49:33 2009 +0200

    Renamed company-electric to company--electric-do.

diff --git a/company.el b/company.el
index 7b51e4f..793af1a 100644
--- a/company.el
+++ b/company.el
@@ -1355,7 +1355,7 @@ To show the number next to the candidates in some 
back-ends, enable
     (erase-buffer)
     (current-buffer)))
 
-(defmacro company-electric (&rest body)
+(defmacro company--electric-do (&rest body)
   (declare (indent 0) (debug t))
   `(when (company-manual-begin)
      (save-window-excursion
@@ -1375,7 +1375,7 @@ To show the number next to the candidates in some 
back-ends, enable
 (defun company-show-doc-buffer ()
   "Temporarily show a buffer with the complete documentation for the 
selection."
   (interactive)
-  (company-electric
+  (company--electric-do
     (let ((selected (nth company-selection company-candidates)))
       (display-buffer (or (company-call-backend 'doc-buffer selected)
                           (error "No documentation available")) t))))
@@ -1384,7 +1384,7 @@ To show the number next to the candidates in some 
back-ends, enable
 (defun company-show-location ()
   "Temporarily display a buffer showing the selected candidate in context."
   (interactive)
-  (company-electric
+  (company--electric-do
     (let* ((selected (nth company-selection company-candidates))
            (location (company-call-backend 'location selected))
            (pos (or (cdr location) (error "No location available")))

commit 6aa6cbdd0ea0dfaaa04c4fd3a08e59ff84a8f73a
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 21 23:21:23 2009 +0200

    Extracted company--good-prefix-p.

diff --git a/company.el b/company.el
index bb2131b..7b51e4f 100644
--- a/company.el
+++ b/company.el
@@ -909,15 +909,17 @@ keymap during active completions (`company-active-map'):
         (company-cancel company-prefix)
         nil)))))
 
+(defun company--good-prefix-p (prefix)
+  (and (stringp prefix)
+       (or (company-explicit-action-p)
+           (>= (length prefix) company-minimum-prefix-length))))
+
 (defun company--continue ()
   (when (company-call-backend 'no-cache company-prefix)
     ;; Don't complete existing candidates, fetch new ones.
     (setq company-candidates-cache nil))
   (let* ((new-prefix (company-call-backend 'prefix))
-         (c (when (and (stringp new-prefix)
-                       (or (company-explicit-action-p)
-                           (>= (length new-prefix)
-                               company-minimum-prefix-length))
+         (c (when (and (company--good-prefix-p new-prefix)
                        (= (- (point) (length new-prefix))
                           (- company-point (length company-prefix))))
               (company-calculate-candidates new-prefix))))
@@ -950,8 +952,7 @@ keymap during active completions (`company-active-map'):
                   (funcall backend 'prefix))
               (company--multi-backend-adapter backend 'prefix)))
       (when prefix
-        (when (and (stringp prefix)
-                   (>= (length prefix) company-minimum-prefix-length))
+        (when (company--good-prefix-p prefix)
           (setq company-backend backend
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.

commit 0ecc01534076197f8e86853b90d2636b454daf7c
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 21 13:53:48 2009 +0200

    Actually use cache in company-files.

diff --git a/company-files.el b/company-files.el
index fa6936e..1fc3c5b 100644
--- a/company-files.el
+++ b/company-files.el
@@ -51,7 +51,6 @@
   (let* ((dir (file-name-directory prefix))
          (file (file-name-nondirectory prefix))
          candidates)
-    (setq company-files-completion-cache nil)
     (unless (equal dir (car company-files-completion-cache))
       (dolist (file (company-files-directory-files dir file))
         (setq file (concat dir file))

commit 4da5874a59d5232ca1c1abedadb1e47d5b0ad14d
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 18:43:24 2009 +0200

    Fixed 'safe-local-variable function typo.

diff --git a/company.el b/company.el
index 007f66e..bb2131b 100644
--- a/company.el
+++ b/company.el
@@ -354,7 +354,7 @@ does not know about.  It should also be callable 
interactively and use
                                      company-safe-backends)
                            (symbol :tag "User defined"))))))
 
-(put 'company-backends 'safe-local-variable 'company-safe-backend-p)
+(put 'company-backends 'safe-local-variable 'company-safe-backends-p)
 
 (defcustom company-completion-started-hook nil
   "*Hook run when company starts completing.

commit fd441ebeadaa49e9eecaf1d20ce7db88d25d5975
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 18:05:49 2009 +0200

    Removed old merge instructions.

diff --git a/company.el b/company.el
index f15344f..007f66e 100644
--- a/company.el
+++ b/company.el
@@ -54,13 +54,9 @@
 ;;     ('meta (format "This value is named %s" arg))))
 ;;
 ;; Sometimes it is a good idea to mix two back-ends together, for example to
-;; enrich gtags with dabbrev text (to emulate local variables):
-;;
-;; (defun gtags-gtags-dabbrev-backend (command &optional arg &rest ignored)
-;;   (case command
-;;     (prefix (company-gtags 'prefix))
-;;     (candidates (append (company-gtags 'candidates arg)
-;;                         (company-dabbrev 'candidates arg)))))
+;; enrich gtags with dabbrev-code results (to emulate local variables):
+;; To do this, add a list with the merged back-ends as an element in
+;; company-backends.
 ;;
 ;; Known Issues:
 ;; When point is at the very end of the buffer, the pseudo-tooltip appears very

commit 0adc65021d1aafe2ae9da3f11c9da81794653b11
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 18:02:42 2009 +0200

    User inner window height for tooltip calculations.

diff --git a/company.el b/company.el
index 4177266..f15344f 100644
--- a/company.el
+++ b/company.el
@@ -1635,11 +1635,15 @@ Example:
 
 ;; show
 
+(defsubst company--window-inner-height ()
+  (let ((edges (window-inside-edges (selected-window))))
+    (- (nth 3 edges) (nth 1 edges))))
+
 (defsubst company--pseudo-tooltip-height ()
   "Calculate the appropriate tooltip height.
 Returns a negative number if the tooltip should be displayed above point."
-  (let* ((lines (1- (count-lines (window-start) (point-at-bol))))
-         (below (- (window-height) 3 lines)))
+  (let* ((lines (count-lines (window-start) (point-at-bol)))
+         (below (- (company--window-inner-height) 1 lines)))
     (if (and (< below (min company-tooltip-minimum company-candidates-length))
              (> lines below))
         (- (max 3 (min company-tooltip-limit lines)))

commit f46517da24e979c288e9e4e21fdf812520cff19e
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 17:46:39 2009 +0200

    Reverted default front-end back to company-preview-if-just-one-frontend.

diff --git a/company.el b/company.el
index 4a766c8..4177266 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Reverted default front-end back to 
`company-preview-if-just-one-frontend'.
 ;;    The pseudo tooltip will no longer be clipped at the right window edge.
 ;;    Added `company-tooltip-minimum'.
 ;;    Windows compatibility fixes.
@@ -215,7 +216,7 @@
   (set variable value))
 
 (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
-                               company-preview-frontend
+                               company-preview-if-just-one-frontend
                                company-echo-metadata-frontend)
   "*The list of active front-ends (visualizations).
 Each front-end is a function that takes one argument.  It is called with

commit 62519305dfb30216714cb17363e0fc76b13677fa
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 17:41:54 2009 +0200

    Shift tooltip left instead of clipping.

diff --git a/company.el b/company.el
index 51427ba..4a766c8 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    The pseudo tooltip will no longer be clipped at the right window edge.
 ;;    Added `company-tooltip-minimum'.
 ;;    Windows compatibility fixes.
 ;;
@@ -1550,6 +1551,11 @@ Example:
     (length lst)))
 
 (defun company--replacement-string (lines old column nl &optional align-top)
+
+  (let ((width (length (car lines))))
+    (when (> width (- (window-width) column))
+      (setq column (max 0 (- (window-width) width)))))
+
   (let (new)
     (when align-top
       ;; untouched lines first
@@ -1565,7 +1571,7 @@ Example:
             (mapconcat 'identity (nreverse new) "\n")
             "\n")))
 
-(defun company-create-lines (column selection limit)
+(defun company--create-lines (selection limit)
 
   (let ((len company-candidates-length)
         (numbered 99999)
@@ -1594,7 +1600,7 @@ Example:
 
     (dotimes (i len)
       (setq width (max (length (pop lines-copy)) width)))
-    (setq width (min width (- (window-width) column)))
+    (setq width (min width (window-width)))
 
     (setq lines-copy lines)
 
@@ -1665,7 +1671,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
         (overlay-put ov 'company-replacement-args args)
         (overlay-put ov 'company-before
                      (apply 'company--replacement-string
-                            (company-create-lines column selection (abs 
height))
+                            (company--create-lines selection (abs height))
                             args))
 
         (overlay-put ov 'company-column column)
@@ -1683,7 +1689,7 @@ Returns a negative number if the tooltip should be 
displayed above point."
         (height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (apply 'company--replacement-string
-                        (company-create-lines column selection height)
+                        (company--create-lines selection height)
                         (overlay-get company-pseudo-tooltip-overlay
                                      'company-replacement-args)))))
 

commit 8e0d3e31414b5e8ed5c0ecf88c91850e0f233b4a
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 16:38:16 2009 +0200

    Merged stored properties in the pseudo-tooltip overlay.

diff --git a/company.el b/company.el
index 681d9c2..51427ba 100644
--- a/company.el
+++ b/company.el
@@ -1644,34 +1644,33 @@ Returns a negative number if the tooltip should be 
displayed above point."
 
     (move-to-column 0)
 
-    (let ((height (company--pseudo-tooltip-height))
-          above lines nl beg end old-string str)
+    (let* ((height (company--pseudo-tooltip-height))
+           above)
 
       (when (< height 0)
         (setq row (+ row height -1)
               above t))
 
-      (setq lines (company-create-lines column selection (abs height))
-            nl (< (move-to-window-line row) row)
-            beg (point)
-            end (save-excursion
-                  (move-to-window-line (+ row (abs height)))
-                  (point))
-            old-string
-            (mapcar 'company-untabify (company-buffer-lines beg end)))
-
-      (setq company-pseudo-tooltip-overlay (make-overlay beg end))
-
-      (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
-      (overlay-put company-pseudo-tooltip-overlay 'company-column column)
-      (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
-      (overlay-put company-pseudo-tooltip-overlay 'company-above above)
-      (overlay-put company-pseudo-tooltip-overlay 'company-before
-                   (company--replacement-string lines old-string column nl
-                                                above))
-      (overlay-put company-pseudo-tooltip-overlay 'company-height (abs height))
-
-      (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
+      (let* ((nl (< (move-to-window-line row) row))
+             (beg (point))
+             (end (save-excursion
+                    (move-to-window-line (+ row (abs height)))
+                    (point)))
+             (ov (make-overlay beg end))
+             (args (list (mapcar 'company-untabify
+                                 (company-buffer-lines beg end))
+                         column nl above)))
+
+        (setq company-pseudo-tooltip-overlay ov)
+        (overlay-put ov 'company-replacement-args args)
+        (overlay-put ov 'company-before
+                     (apply 'company--replacement-string
+                            (company-create-lines column selection (abs 
height))
+                            args))
+
+        (overlay-put ov 'company-column column)
+        (overlay-put ov 'company-height (abs height))
+        (overlay-put ov 'window (selected-window))))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (company--col-row pos)))
@@ -1680,15 +1679,13 @@ Returns a negative number if the tooltip should be 
displayed above point."
                                    company-selection))))
 
 (defun company-pseudo-tooltip-edit (lines selection)
-  (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
-         (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
-         (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
-         (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
-         (above (overlay-get company-pseudo-tooltip-overlay 'company-above))
-         (lines (company-create-lines column selection (abs height))))
+  (let ((column (overlay-get company-pseudo-tooltip-overlay 'company-column))
+        (height (overlay-get company-pseudo-tooltip-overlay 'company-height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
-                 (company--replacement-string lines old-string column nl
-                                              above))))
+                 (apply 'company--replacement-string
+                        (company-create-lines column selection height)
+                        (overlay-get company-pseudo-tooltip-overlay
+                                     'company-replacement-args)))))
 
 (defun company-pseudo-tooltip-hide ()
   (when company-pseudo-tooltip-overlay

commit 61cdf2ccc9350cc17c8d5f9381eb90e6d8ec6358
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 16:31:10 2009 +0200

    Changed argument order in company--replacement-string.

diff --git a/company.el b/company.el
index 6b7a427..681d9c2 100644
--- a/company.el
+++ b/company.el
@@ -1549,7 +1549,7 @@ Example:
       limit
     (length lst)))
 
-(defun company-replacement-string (old lines column nl &optional align-top)
+(defun company--replacement-string (lines old column nl &optional align-top)
   (let (new)
     (when align-top
       ;; untouched lines first
@@ -1667,8 +1667,8 @@ Returns a negative number if the tooltip should be 
displayed above point."
       (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
       (overlay-put company-pseudo-tooltip-overlay 'company-above above)
       (overlay-put company-pseudo-tooltip-overlay 'company-before
-                   (company-replacement-string old-string lines column nl
-                                               above))
+                   (company--replacement-string lines old-string column nl
+                                                above))
       (overlay-put company-pseudo-tooltip-overlay 'company-height (abs height))
 
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
@@ -1687,8 +1687,8 @@ Returns a negative number if the tooltip should be 
displayed above point."
          (above (overlay-get company-pseudo-tooltip-overlay 'company-above))
          (lines (company-create-lines column selection (abs height))))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
-                 (company-replacement-string old-string lines column nl
-                                             above))))
+                 (company--replacement-string lines old-string column nl
+                                              above))))
 
 (defun company-pseudo-tooltip-hide ()
   (when company-pseudo-tooltip-overlay

commit 8c143040bc70c63a9b6c031584ed07381bdf603e
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 16:20:03 2009 +0200

    Added company-tooltip-minimum.

diff --git a/company.el b/company.el
index d1cf5cc..6b7a427 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-tooltip-minimum'.
 ;;    Windows compatibility fixes.
 ;;
 ;; 2009-04-19 (0.4.1)
@@ -255,6 +256,12 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
   :group 'company
   :type 'integer)
 
+(defcustom company-tooltip-minimum 6
+  "*The minimum height of the tool tip.
+If this many lines are not available, prefer to display the tooltip above."
+  :group 'company
+  :type 'integer)
+
 (defvar company-safe-backends
   '((company-abbrev . "Abbrev")
     (company-css . "CSS")
@@ -1537,9 +1544,18 @@ Example:
           new
           (company-safe-substring old (+ offset (length new)))))
 
-(defun company-replacement-string (old lines column nl)
+(defsubst company--length-limit (lst limit)
+  (if (nthcdr limit lst)
+      limit
+    (length lst)))
+
+(defun company-replacement-string (old lines column nl &optional align-top)
   (let (new)
-    ;; Inject into old lines.
+    (when align-top
+      ;; untouched lines first
+      (dotimes (i (- (length old) (length lines)))
+        (push (pop old) new)))
+    ;; length into old lines.
     (while old
       (push (company-modify-line (pop old) (pop lines) column) new))
     ;; Append whole new lines.
@@ -1612,11 +1628,15 @@ Example:
 
 ;; show
 
-(defsubst company-pseudo-tooltip-height ()
-  "Calculate the appropriate tooltip height."
-  (max 3 (min company-tooltip-limit
-              (- (window-height) 2
-                 (count-lines (window-start) (point-at-bol))))))
+(defsubst company--pseudo-tooltip-height ()
+  "Calculate the appropriate tooltip height.
+Returns a negative number if the tooltip should be displayed above point."
+  (let* ((lines (1- (count-lines (window-start) (point-at-bol))))
+         (below (- (window-height) 3 lines)))
+    (if (and (< below (min company-tooltip-minimum company-candidates-length))
+             (> lines below))
+        (- (max 3 (min company-tooltip-limit lines)))
+      (max 3 (min company-tooltip-limit below)))))
 
 (defun company-pseudo-tooltip-show (row column selection)
   (company-pseudo-tooltip-hide)
@@ -1624,25 +1644,32 @@ Example:
 
     (move-to-column 0)
 
-    (let* ((height (company-pseudo-tooltip-height))
-           (lines (company-create-lines column selection height))
-           (nl (< (move-to-window-line row) row))
-           (beg (point))
-           (end (save-excursion
-                  (move-to-window-line (+ row height))
-                  (point)))
-           (old-string
+    (let ((height (company--pseudo-tooltip-height))
+          above lines nl beg end old-string str)
+
+      (when (< height 0)
+        (setq row (+ row height -1)
+              above t))
+
+      (setq lines (company-create-lines column selection (abs height))
+            nl (< (move-to-window-line row) row)
+            beg (point)
+            end (save-excursion
+                  (move-to-window-line (+ row (abs height)))
+                  (point))
+            old-string
             (mapcar 'company-untabify (company-buffer-lines beg end)))
-           str)
 
       (setq company-pseudo-tooltip-overlay (make-overlay beg end))
 
       (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
       (overlay-put company-pseudo-tooltip-overlay 'company-column column)
       (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
+      (overlay-put company-pseudo-tooltip-overlay 'company-above above)
       (overlay-put company-pseudo-tooltip-overlay 'company-before
-                   (company-replacement-string old-string lines column nl))
-      (overlay-put company-pseudo-tooltip-overlay 'company-height height)
+                   (company-replacement-string old-string lines column nl
+                                               above))
+      (overlay-put company-pseudo-tooltip-overlay 'company-height (abs height))
 
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
@@ -1657,9 +1684,11 @@ Example:
          (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
          (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
          (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
-         (lines (company-create-lines column selection height)))
+         (above (overlay-get company-pseudo-tooltip-overlay 'company-above))
+         (lines (company-create-lines column selection (abs height))))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
-                 (company-replacement-string old-string lines column nl))))
+                 (company-replacement-string old-string lines column nl
+                                             above))))
 
 (defun company-pseudo-tooltip-hide ()
   (when company-pseudo-tooltip-overlay
@@ -1683,13 +1712,16 @@ Example:
   (case command
     ('pre-command (company-pseudo-tooltip-hide-temporarily))
     ('post-command
-     (unless (and (overlayp company-pseudo-tooltip-overlay)
-                  (equal (overlay-get company-pseudo-tooltip-overlay
-                                      'company-height)
-                         (company-pseudo-tooltip-height)))
-       ;; Redraw needed.
-       (company-pseudo-tooltip-show-at-point (- (point)
-                                                (length company-prefix))))
+     (let ((old-height (if (overlayp company-pseudo-tooltip-overlay)
+                           (overlay-get company-pseudo-tooltip-overlay
+                                        'company-height)
+                         0))
+           (new-height (company--pseudo-tooltip-height)))
+       (unless (and (>= (* old-height new-height) 0)
+                    (>= (abs old-height) (abs new-height)))
+         ;; Redraw needed.
+         (company-pseudo-tooltip-show-at-point (- (point)
+                                                  (length company-prefix)))))
      (company-pseudo-tooltip-unhide))
     ('hide (company-pseudo-tooltip-hide)
            (setq company-tooltip-offset 0))

commit bce184dc2426105f6d45499e9cd99b59981b8dcc
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 16:05:43 2009 +0200

    Moved company-tooltip-limit into defcustom section.

diff --git a/company.el b/company.el
index 84db310..d1cf5cc 100644
--- a/company.el
+++ b/company.el
@@ -165,11 +165,6 @@
   "*Face used for the selected common completion in the tool tip."
   :group 'company)
 
-(defcustom company-tooltip-limit 10
-  "*The maximum number of candidates in the tool tip"
-  :group 'company
-  :type 'integer)
-
 (defface company-preview
   '((t :background "blue4"
        :foreground "wheat"))
@@ -255,6 +250,11 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
+(defcustom company-tooltip-limit 10
+  "*The maximum number of candidates in the tool tip"
+  :group 'company
+  :type 'integer)
+
 (defvar company-safe-backends
   '((company-abbrev . "Abbrev")
     (company-css . "CSS")

commit 1544e6e84655ae58ca65aa4456c037ce471117bf
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 14:13:41 2009 +0200

    Show current back-end in lighter.

diff --git a/company.el b/company.el
index d3caee6..84db310 100644
--- a/company.el
+++ b/company.el
@@ -510,6 +510,11 @@ The work-around consists of adding a newline.")
         nil)
     (mapc 'company-init-backend backend)))
 
+(defvar company-default-lighter " company")
+
+(defvar company-lighter company-default-lighter)
+(make-variable-buffer-local 'company-lighter)
+
 ;;;###autoload
 (define-minor-mode company-mode
   "\"complete anything\"; in in-buffer completion framework.
@@ -535,7 +540,7 @@ regular keymap (`company-mode-map'):
 keymap during active completions (`company-active-map'):
 
 \\{company-active-map}"
-  nil " comp" company-mode-map
+  nil company-lighter company-mode-map
   (if company-mode
       (progn
         (add-hook 'pre-command-hook 'company-pre-command nil t)
@@ -946,7 +951,8 @@ keymap during active completions (`company-active-map'):
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
           (when (consp c)
-            (setq company-prefix prefix)
+            (setq company-prefix prefix
+                  company-lighter (concat " " (symbol-name backend)))
             (company-update-candidates c)
             (run-hook-with-args 'company-completion-started-hook
                                 (company-explicit-action-p))
@@ -989,6 +995,7 @@ keymap during active completions (`company-active-map'):
         company-selection 0
         company-selection-changed nil
         company--explicit-action nil
+        company-lighter company-default-lighter
         company--point-max nil
         company-point nil)
   (when company-timer

commit fd9bd300bec3838ee3a5b8424938c1cc5a2a781d
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 18:27:56 2009 +0200

    Added Windows support to company-files.

diff --git a/company-files.el b/company-files.el
index fa9666d..fa6936e 100644
--- a/company-files.el
+++ b/company-files.el
@@ -26,13 +26,20 @@
         (directory-files dir nil "\\`[^.]\\|\\`.[^.]")
       (file-name-all-completions prefix dir))))
 
+(defvar company-files-regexps
+  (let ((begin (if (eq system-type 'windows-nt)
+                   "[a-z][A-Z]\\"
+                 "~?/")))
+    (list (concat "\"\\(" begin "[^\"\n]*\\)")
+          (concat "\'\\(" begin "[^\'\n]*\\)")
+          (concat "\\(?:[ \t]\\|^\\)\\(" begin "[^ \t\n]*\\)"))))
+
 (defun company-files-grab-existing-name ()
   ;; Grab file names with spaces, only when they include quotes.
-  (let ((file (or (company-grab-line "\"\\(~?/[^\"\n]*\\)" 1)
-                  (company-grab-line "\'\\(~?/[^\'\n]*\\)" 1)
-                  (company-grab-line "[ \t\n]\\(~?/[^ \t\n]*\\)" 1)))
-        dir)
-    (and file
+  (let (file dir)
+    (and (dolist (regexp company-files-regexps)
+           (when (setq file (company-grab-line regexp 1))
+             (return file)))
          (setq dir (file-name-directory file))
          (file-exists-p dir)
          (file-name-all-completions (file-name-nondirectory file) dir)

commit d503ff5fd70d310d5e71ae21f2ba8568d293b2f1
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 14:00:56 2009 +0200

    Added Windows root dir compatibility fixes.

diff --git a/company-eclim.el b/company-eclim.el
index a3c32a6..4b8a5c9 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -74,23 +74,11 @@ eclim can only complete correctly when the buffer has been 
saved."
   (mapcar (lambda (line) (nreverse (split-string line " *- *" nil)))
           (company-eclim--call-process "project_list")))
 
-(defun company-eclim--locate-dominating-file (file name)
-  (catch 'root
-    (let ((dir (file-name-directory buffer-file-name)))
-      (while (not (equal dir "/"))
-        (when (file-exists-p (expand-file-name name dir))
-          (throw 'root dir))
-        (setq dir (file-name-directory (directory-file-name dir)))))))
-
 (defun company-eclim--project-dir ()
   (if (eq company-eclim--project-dir 'unknown)
       (setq company-eclim--project-dir
             (directory-file-name
-             (if (fboundp 'locate-dominating-file)
-                 (expand-file-name (locate-dominating-file buffer-file-name
-                                                           ".project"))
-               (company-eclim--locate-dominating-file buffer-file-name
-                                                     ".project"))))
+             (company-locate-dominating-file buffer-file-name ".project")))
     company-eclim--project-dir))
 
 (defun company-eclim--project-name ()
diff --git a/company-etags.el b/company-etags.el
index ac9da57..a5080cd 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -36,16 +36,11 @@ buffer automatically."
 (make-variable-buffer-local 'company-etags-buffer-table)
 
 (defun company-etags-find-table ()
-  (let ((dir (if buffer-file-name
-                 (file-name-directory buffer-file-name)
-               (expand-file-name default-directory)))
-        file)
-    (while (not (or file (equal dir "/")))
-      (unless (file-exists-p (setq file (expand-file-name "TAGS" dir)))
-        (setq file nil
-              dir (file-name-directory (directory-file-name dir)))))
+  (let ((file (company-locate-dominating-file (or buffer-file-name
+                                                  default-directory)
+                                              "TAGS")))
     (when file
-      (list file))))
+      (list (expand-file-name file)))))
 
 (defun company-etags-buffer-table ()
   (or (and company-etags-use-main-table-list tags-table-list)
diff --git a/company-xcode.el b/company-xcode.el
index e2e3be3..df76a57 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -79,9 +79,11 @@ valid in most contexts."
   (let ((dir (if buffer-file-name
                  (file-name-directory buffer-file-name)
                (expand-file-name default-directory)))
+        (prev-dir nil)
         file)
-    (while (not (or file (equal dir "/")))
+    (while (not (or file (equal dir prev-dir)))
       (setq file (car (directory-files dir t ".xcodeproj\\'" t))
+            prev-dir dir
             dir (file-name-directory (directory-file-name dir))))
     file))
 
diff --git a/company.el b/company.el
index 8ea6711..d3caee6 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Windows compatibility fixes.
+;;
 ;; 2009-04-19 (0.4.1)
 ;;    Added `global-company-mode'.
 ;;    Performance enhancements.
@@ -633,6 +635,18 @@ keymap during active completions (`company-active-map'):
         (car (setq ppss (cdr ppss)))
         (nth 3 ppss))))
 
+(if (fboundp 'locate-dominating-file)
+    (defalias 'company-locate-dominating-file 'locate-dominating-file)
+  (defun company-locate-dominating-file (file name)
+    (catch 'root
+      (let ((dir (file-name-directory file))
+            (prev-dir nil))
+        (while (not (equal dir prev-dir))
+          (when (file-exists-p (expand-file-name name dir))
+            (throw 'root dir))
+          (setq prev-dir dir
+                dir (file-name-directory (directory-file-name dir))))))))
+
 (defun company-call-backend (&rest args)
   (if (functionp company-backend)
       (apply company-backend args)

commit 2488744791e04650653d75c1b34b06e8d2e58839
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 20 14:06:04 2009 +0200

    Added missing GPL header to company-eclim.el.

diff --git a/company-eclim.el b/company-eclim.el
index 818567b..a3c32a6 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -1,3 +1,22 @@
+;;; company-eclim.el --- a company-mode completion back-end for eclim.
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.4.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (eval-when-compile (require 'cl))
 

commit 404796461a1ecf64c7290c9c5a4f52c98f69227c
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 17:53:24 2009 +0200

    Mention save requirement in for eclim back-end.

diff --git a/company-eclim.el b/company-eclim.el
index 00c3922..818567b 100644
--- a/company-eclim.el
+++ b/company-eclim.el
@@ -106,7 +106,10 @@ eclim can only complete correctly when the buffer has been 
saved."
 
 (defun company-eclim (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for eclim.
-eclim provides access to Eclipse Java IDE features for other editors."
+eclim provides access to Eclipse Java IDE features for other editors.
+
+Completions only work correctly when the buffer has been saved.
+`company-eclim-auto-save' determines whether to do this automatically."
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-eclim))

commit b983f9d4b5f807755878e6575fd30c8cdf8700f2
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 13:34:33 2009 +0200

    Bumped version to 0.4.1.

diff --git a/company-abbrev.el b/company-abbrev.el
index 0394e10..70e93af 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index 720a459..d08f414 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index a5832e7..a2efcaa 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 3a686b9..b80ab3d 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index 486f4fe..98d335a 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index 3df6963..ac9da57 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 9f5fb1d..fa9666d 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 754b3eb..d279899 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index bf632d3..b6ec708 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-keywords.el b/company-keywords.el
index 7e1698c..ca763b0 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 6ee2cc6..7466ada 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 92f790f..247a38f 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index 4d23bf6..ab28541 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index b3e6261..13c0162 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 5e7b813..e2e3be3 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.4.
+;; This file is part of company 0.4.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index d84a8c3..8ea6711 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.4
+;; Version: 0.4.1
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-19 (0.4.1)
 ;;    Added `global-company-mode'.
 ;;    Performance enhancements.
 ;;    Added `company-eclim' back-end.

commit bb08b9f3d93019a35ed99e1eb08fcb26d91cadab
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 13:50:29 2009 +0200

    Don't warn twice about failing back-ends.

diff --git a/company.el b/company.el
index 20f490e..d84a8c3 100644
--- a/company.el
+++ b/company.el
@@ -488,6 +488,8 @@ The work-around consists of adding a newline.")
     keymap)
   "Keymap that is enabled during an active completion.")
 
+(defvar company--disabled-backends nil)
+
 (defun company-init-backend (backend)
   (and (symbolp backend)
        (not (fboundp backend))
@@ -498,8 +500,10 @@ The work-around consists of adding a newline.")
       (if (ignore-errors (funcall backend 'init) t)
           (put backend 'company-init t)
         (put backend 'company-init 'failed)
-        (message "Company back-end '%s' could not be initialized"
-                 backend)
+        (unless (memq backend company--disabled-backends)
+          (message "Company back-end '%s' could not be initialized"
+                   backend)
+          (push backend company--disabled-backends))
         nil)
     (mapc 'company-init-backend backend)))
 

commit e23e0b682729340266add858a1db960f40d655ef
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 13:30:44 2009 +0200

    Added global-company-mode.

diff --git a/company.el b/company.el
index 21de561..20f490e 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `global-company-mode'.
 ;;    Performance enhancements.
 ;;    Added `company-eclim' back-end.
 ;;    Added safer workaround for Emacs `posn-col-row' bug.
@@ -538,6 +539,9 @@ keymap during active completions (`company-active-map'):
     (company-cancel)
     (kill-local-variable 'company-point)))
 
+(define-globalized-minor-mode global-company-mode company-mode
+  (lambda () (company-mode 1)))
+
 (defsubst company-assert-enabled ()
   (unless company-mode
     (company-uninstall-map)

commit c4eb4f7f4410647102dc53718535c4fdb53fd260
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 12:56:03 2009 +0200

    Use timer slightly more efficiently.

diff --git a/company.el b/company.el
index c45dde0..21de561 100644
--- a/company.el
+++ b/company.el
@@ -998,7 +998,8 @@ keymap during active completions (`company-active-map'):
              (message "%s" (error-message-string err))
              (company-cancel))))
   (when company-timer
-    (cancel-timer company-timer))
+    (cancel-timer company-timer)
+    (setq company-timer nil))
   (company-uninstall-map))
 
 (defun company-post-command ()
@@ -1007,15 +1008,16 @@ keymap during active completions (`company-active-map'):
         (progn
           (unless (equal (point) company-point)
             (company-begin))
-          (when company-candidates
-            (company-call-frontends 'post-command))
-          (and (numberp company-idle-delay)
-               (or (eq t company-begin-commands)
-                   (memq this-command company-begin-commands))
-               (setq company-timer
-                     (run-with-timer company-idle-delay nil 'company-idle-begin
-                                     (current-buffer) (selected-window)
-                                     (buffer-chars-modified-tick) (point)))))
+          (if company-candidates
+              (company-call-frontends 'post-command)
+            (and (numberp company-idle-delay)
+                 (or (eq t company-begin-commands)
+                     (memq this-command company-begin-commands))
+                 (setq company-timer
+                       (run-with-timer company-idle-delay nil
+                                       'company-idle-begin
+                                       (current-buffer) (selected-window)
+                                       (buffer-chars-modified-tick) 
(point))))))
       (error (message "Company: An error occurred in post-command")
              (message "%s" (error-message-string err))
              (company-cancel))))

commit 3512bdcef702f40f549babdd8ba2ef945c380b97
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 12:51:10 2009 +0200

    Added company-auto-begin.

diff --git a/company.el b/company.el
index df5df8a..c45dde0 100644
--- a/company.el
+++ b/company.el
@@ -802,19 +802,22 @@ keymap during active completions (`company-active-map'):
            (company-input-noop)
            (company-post-command)))))
 
-(defun company-manual-begin ()
-  (interactive)
+(defun company-auto-begin ()
   (company-assert-enabled)
   (and company-mode
        (not company-candidates)
        (let ((company-idle-delay t)
              (company-minimum-prefix-length 0)
              (company-begin-commands t))
-         (setq company--explicit-action t)
          (company-begin)))
   ;; Return non-nil if active.
   company-candidates)
 
+(defun company-manual-begin ()
+  (interactive)
+  (setq company--explicit-action t)
+  (company-auto-begin))
+
 (defun company-require-match-p ()
   (let ((backend-value (company-call-backend 'require-match)))
     (or (eq backend-value t)

commit 64e3ea90b905dcb94e7976910f0421839808c5fd
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 12:28:30 2009 +0200

    Don't call cancel if completion didn't start.

diff --git a/company.el b/company.el
index fd467cc..df5df8a 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Performance enhancements.
 ;;    Added `company-eclim' back-end.
 ;;    Added safer workaround for Emacs `posn-col-row' bug.
 ;;
@@ -884,17 +885,18 @@ keymap during active completions (`company-active-map'):
                        (= (- (point) (length new-prefix))
                           (- company-point (length company-prefix))))
               (company-calculate-candidates new-prefix))))
-    (cond
-     ((eq c t)
-      ;; t means complete/unique.
-      (company-cancel new-prefix)
-      nil)
-     ((consp c)
-      ;; incremental match
-      (setq company-prefix new-prefix)
-      (company-update-candidates c)
-      c)
-     (t (company--continue-failed new-prefix)))))
+    (or (cond
+         ((eq c t)
+          ;; t means complete/unique.
+          (company-cancel new-prefix)
+          nil)
+         ((consp c)
+          ;; incremental match
+          (setq company-prefix new-prefix)
+          (company-update-candidates c)
+          c)
+         (t (company--continue-failed new-prefix)))
+        (company-cancel))))
 
 (defun company--begin-new ()
   (let (prefix c)
@@ -915,10 +917,10 @@ keymap during active completions (`company-active-map'):
         (when (and (stringp prefix)
                    (>= (length prefix) company-minimum-prefix-length))
           (setq company-backend backend
-                company-prefix prefix
                 c (company-calculate-candidates prefix))
           ;; t means complete/unique.  We don't start, so no hooks.
           (when (consp c)
+            (setq company-prefix prefix)
             (company-update-candidates c)
             (run-hook-with-args 'company-completion-started-hook
                                 (company-explicit-action-p))
@@ -929,16 +931,14 @@ keymap during active completions (`company-active-map'):
   (setq company-candidates
         (or (and company-candidates (company--continue))
             (and (company--should-complete) (company--begin-new))))
-  (if company-candidates
-      (progn
-        (when (and company-end-of-buffer-workaround (eobp))
-          (save-excursion (insert "\n"))
-          (setq company-added-newline (buffer-chars-modified-tick)))
-        (setq company-point (point)
-              company--point-max (point-max))
-        (company-enable-overriding-keymap company-active-map)
-        (company-call-frontends 'update))
-    (company-cancel)))
+  (when company-candidates
+    (when (and company-end-of-buffer-workaround (eobp))
+      (save-excursion (insert "\n"))
+      (setq company-added-newline (buffer-chars-modified-tick)))
+    (setq company-point (point)
+          company--point-max (point-max))
+    (company-enable-overriding-keymap company-active-map)
+    (company-call-frontends 'update)))
 
 (defun company-cancel (&optional result)
   (and company-added-newline

commit e7c7ba09d9b0bd859b0561009be5eab5020593ed
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 11:37:24 2009 +0200

    Fixed wrong case completions.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index b0ca8f9..a5832e7 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -70,7 +70,7 @@ comments or strings."
                       (apply 'derived-mode-p company-dabbrev-code-modes))
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((case-fold-search nil))
+    ('candidates (let ((completion-ignore-case nil))
                    (company-dabbrev--search
                     (company-dabbrev-code--make-regexp arg)
                     company-dabbrev-code-time-limit
diff --git a/company-keywords.el b/company-keywords.el
index 4bddd83..7e1698c 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -149,7 +149,7 @@
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
     ('candidates
-     (let ((case-fold-search nil)
+     (let ((completion-ignore-case nil)
            (symbols (cdr (assq major-mode company-keywords-alist))))
        (all-completions arg (if (consp symbols)
                                 symbols

commit 1043e0e403e1e950b1ffec7803236b2e62c72be7
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 11:35:45 2009 +0200

    Start timer only after company-begin-commands.

diff --git a/company.el b/company.el
index f4b9288..fd467cc 100644
--- a/company.el
+++ b/company.el
@@ -677,8 +677,6 @@ keymap during active completions (`company-active-map'):
 (defvar company--point-max nil)
 (make-variable-buffer-local 'company--point-max)
 
-(defvar company--this-command nil)
-
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
@@ -705,7 +703,7 @@ keymap during active completions (`company-active-map'):
                 overriding-local-map))
        (eq company-idle-delay t)
        (or (eq t company-begin-commands)
-           (memq company--this-command company-begin-commands)
+           (memq this-command company-begin-commands)
            (and (symbolp this-command) (get this-command 'company-begin)))
        (not (and transient-mark-mode mark-active))))
 
@@ -796,7 +794,8 @@ keymap during active completions (`company-active-map'):
        (eq pos (point))
        (not company-candidates)
        (not (equal (point) company-point))
-       (let ((company-idle-delay t))
+       (let ((company-idle-delay t)
+             (company-begin-commands t))
          (company-begin)
          (when company-candidates
            (company-input-noop)
@@ -1003,16 +1002,17 @@ keymap during active completions (`company-active-map'):
   (unless (company-keep this-command)
     (condition-case err
         (progn
-          (setq company--this-command this-command)
           (unless (equal (point) company-point)
             (company-begin))
           (when company-candidates
             (company-call-frontends 'post-command))
-          (when (numberp company-idle-delay)
-            (setq company-timer
-                  (run-with-timer company-idle-delay nil 'company-idle-begin
-                                  (current-buffer) (selected-window)
-                                  (buffer-chars-modified-tick) (point)))))
+          (and (numberp company-idle-delay)
+               (or (eq t company-begin-commands)
+                   (memq this-command company-begin-commands))
+               (setq company-timer
+                     (run-with-timer company-idle-delay nil 'company-idle-begin
+                                     (current-buffer) (selected-window)
+                                     (buffer-chars-modified-tick) (point)))))
       (error (message "Company: An error occurred in post-command")
              (message "%s" (error-message-string err))
              (company-cancel))))

commit f5c886d1beaf8481516c0c7de3d240f3d95d3c69
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 11:28:15 2009 +0200

    Added company-eclim.

diff --git a/company-eclim.el b/company-eclim.el
new file mode 100644
index 0000000..00c3922
--- /dev/null
+++ b/company-eclim.el
@@ -0,0 +1,125 @@
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defun company-eclim-executable-find ()
+  (let (file)
+    (dolist (eclipse-root '("/Applications/eclipse" "/usr/lib/eclipse"
+                            "/usr/local/lib/eclipse"))
+      (and (file-exists-p (setq file (expand-file-name "plugins" 
eclipse-root)))
+           (setq file (car (last (directory-files file t "^org.eclim_"))))
+           (file-exists-p (setq file (expand-file-name "bin/eclim" file)))
+           (return file)))))
+
+(defcustom company-eclim-executable
+  (or (executable-find "eclim") (company-eclim-executable-find))
+  "*Location of eclim executable"
+  :group 'company
+  :type 'file)
+
+(defcustom company-eclim-auto-save nil
+  "*Determines whether to save the buffer when retrieving completions.
+eclim can only complete correctly when the buffer has been saved."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" t)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-eclim--project-dir 'unknown)
+(make-variable-buffer-local 'company-eclim--project-dir)
+
+(defvar company-eclim--project-name 'unknown)
+(make-variable-buffer-local 'company-eclim--project-name)
+
+(defvar company-eclim--doc nil)
+(make-variable-buffer-local 'company-eclim--doc)
+
+(defun company-eclim--buffer-lines ()
+  (goto-char (point-max))
+  (let (lines)
+    (while (= 0 (forward-line -1))
+      (push (buffer-substring-no-properties (point-at-bol) (point-at-eol))
+            lines))
+    lines))
+
+(defun company-eclim--call-process (&rest args)
+  (let ((coding-system-for-read 'utf-8))
+    (with-temp-buffer
+      (if (= 0 (apply 'call-process company-eclim-executable nil t nil
+                      "-command" args))
+          (company-eclim--buffer-lines)
+        (message "Company-eclim command failed")
+        nil))))
+
+(defun company-eclim--project-list ()
+  (mapcar (lambda (line) (nreverse (split-string line " *- *" nil)))
+          (company-eclim--call-process "project_list")))
+
+(defun company-eclim--locate-dominating-file (file name)
+  (catch 'root
+    (let ((dir (file-name-directory buffer-file-name)))
+      (while (not (equal dir "/"))
+        (when (file-exists-p (expand-file-name name dir))
+          (throw 'root dir))
+        (setq dir (file-name-directory (directory-file-name dir)))))))
+
+(defun company-eclim--project-dir ()
+  (if (eq company-eclim--project-dir 'unknown)
+      (setq company-eclim--project-dir
+            (directory-file-name
+             (if (fboundp 'locate-dominating-file)
+                 (expand-file-name (locate-dominating-file buffer-file-name
+                                                           ".project"))
+               (company-eclim--locate-dominating-file buffer-file-name
+                                                     ".project"))))
+    company-eclim--project-dir))
+
+(defun company-eclim--project-name ()
+  (if (eq company-eclim--project-name 'unknown)
+      (setq company-eclim--project-name
+            (car (cddr (assoc (company-eclim--project-dir)
+                              (company-eclim--project-list)))))
+    company-eclim--project-name))
+
+(defun company-eclim--candidates (prefix)
+  (interactive "d")
+  (let ((project-file (file-relative-name buffer-file-name
+                                          (company-eclim--project-dir)))
+        (project-name (company-eclim--project-name)))
+    (when company-eclim-auto-save
+      (save-buffer)
+      ;; FIXME: Sometimes this isn't finished when we complete.
+      (company-eclim--call-process "java_src_update"
+                                  "-p" (company-eclim--project-name)
+                                  "-f" project-file))
+    (setq company-eclim--doc
+          (mapcar (lambda (line)
+                    (cdr (split-string line "|" nil)))
+                  (company-eclim--call-process
+                   "java_complete" "-p" (company-eclim--project-name)
+                   "-f" project-file
+                   "-o" (number-to-string (1- (point)))
+                   "-e" "utf-8"
+                   "-l" "standard"))))
+  (let ((completion-ignore-case nil))
+    (all-completions prefix (mapcar 'car company-eclim--doc))))
+
+(defun company-eclim (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for eclim.
+eclim provides access to Eclipse Java IDE features for other editors."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-eclim))
+    ('prefix (and (derived-mode-p 'java-mode 'jde-mode)
+                  buffer-file-name
+                  company-eclim-executable
+                  (company-eclim--project-name)
+                  (not (company-in-string-or-comment))
+                  (or (company-grab-symbol) 'stop)))
+    ('candidates (company-eclim--candidates arg))
+    ('meta (cadr (assoc arg company-eclim--doc)))
+    ;; because "" doesn't return everything
+    ('no-cache (equal arg ""))))
+
+(provide 'company-eclim)
+;;; company-eclim.el ends here
diff --git a/company.el b/company.el
index 0bec45b..f4b9288 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-eclim' back-end.
 ;;    Added safer workaround for Emacs `posn-col-row' bug.
 ;;
 ;; 2009-04-18 (0.4)
@@ -254,6 +255,7 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
     (company-css . "CSS")
     (company-dabbrev . "dabbrev for plain text")
     (company-dabbrev-code . "dabbrev for code")
+    (company-eclim . "eclim (an Eclipse interace)")
     (company-elisp . "Emacs Lisp")
     (company-etags . "etags")
     (company-files . "Files")
@@ -276,7 +278,7 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                 (return t))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-xcode
+                              company-eclim company-semantic company-xcode
                               (company-gtags company-etags company-dabbrev-code
                                company-keywords)
                               company-oddmuse company-files company-dabbrev)

commit e292e02762db36da86505c99a8b3cbb0f10f2faa
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 00:38:59 2009 +0200

    Don't call back-end again when cache lookup failed.

diff --git a/company.el b/company.el
index f17d7a7..0bec45b 100644
--- a/company.el
+++ b/company.el
@@ -753,30 +753,32 @@ keymap during active completions (`company-active-map'):
     (setq company-candidates nil)))
 
 (defun company-calculate-candidates (prefix)
-  (let ((candidates
-         (or (cdr (assoc prefix company-candidates-cache))
-             (when company-candidates-cache
-               (let ((len (length prefix))
-                     (completion-ignore-case (company-call-backend
-                                              'ignore-case))
-                     prev)
-                 (dotimes (i (1+ len))
-                   (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
-                                                company-candidates-cache)))
-                     (return (all-completions prefix prev))))))
-             (let ((c (company-call-backend 'candidates prefix)))
-               (when company-candidates-predicate
-                 (setq c (company-apply-predicate
-                          c company-candidates-predicate)))
-               (unless (company-call-backend 'sorted)
-                 (setq c (sort c 'string<)))
-               (when (company-call-backend 'duplicates)
-                 ;; strip duplicates
-                 (let ((c2 c))
-                   (while c2
-                     (setcdr c2 (progn (while (equal (pop c2) (car c2)))
-                                       c2)))))
-               c))))
+  (let ((candidates (cdr (assoc prefix company-candidates-cache))))
+    (or candidates
+        (when company-candidates-cache
+          (let ((len (length prefix))
+                (completion-ignore-case (company-call-backend 'ignore-case))
+                prev)
+            (dotimes (i (1+ len))
+              (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                           company-candidates-cache)))
+                (setq candidates (all-completions prefix prev))
+                (return t)))))
+        ;; no cache match, call back-end
+        (progn
+          (setq candidates (company-call-backend 'candidates prefix))
+          (when company-candidates-predicate
+            (setq candidates
+                  (company-apply-predicate candidates
+                                           company-candidates-predicate)))
+          (unless (company-call-backend 'sorted)
+            (setq candidates (sort candidates 'string<)))
+          (when (company-call-backend 'duplicates)
+            ;; strip duplicates
+            (let ((c2 candidates))
+              (while c2
+                (setcdr c2 (progn (while (equal (pop c2) (car c2)))
+                                  c2)))))))
     (if (or (cdr candidates)
             (not (equal (car candidates) prefix)))
         ;; Don't start when already completed and unique.

commit 89c96799ce2d7bd6fd28544a6082ac86240065c3
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 19 00:14:02 2009 +0200

    Handle uninitialized back-ends.

diff --git a/company.el b/company.el
index 6884bd5..f17d7a7 100644
--- a/company.el
+++ b/company.el
@@ -493,8 +493,10 @@ The work-around consists of adding a newline.")
           (functionp backend))
       (if (ignore-errors (funcall backend 'init) t)
           (put backend 'company-init t)
+        (put backend 'company-init 'failed)
         (message "Company back-end '%s' could not be initialized"
-                 backend))
+                 backend)
+        nil)
     (mapc 'company-init-backend backend)))
 
 ;;;###autoload
@@ -901,7 +903,9 @@ keymap during active completions (`company-active-map'):
             (if (or (symbolp backend)
                     (functionp backend))
                 (when (or (not (symbolp backend))
-                          (get backend 'company-init))
+                          (eq t (get backend 'company-init))
+                          (unless (get backend 'company-init)
+                            (company-init-backend backend)))
                   (funcall backend 'prefix))
               (company--multi-backend-adapter backend 'prefix)))
       (when prefix

commit 9c10e3cebd16aa24714cc152d46055e3c7d61db7
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 18 18:27:25 2009 +0200

    Don't consider backward-delete-char-untabify incremental.
    
    It replaces a tab with spaces, so the number of characters increases.

diff --git a/company.el b/company.el
index 64c7bc9..6884bd5 100644
--- a/company.el
+++ b/company.el
@@ -836,6 +836,7 @@ keymap during active completions (`company-active-map'):
 (defun company--incremental-p ()
   (and (> (point) company-point)
        (> (point-max) company--point-max)
+       (not (eq this-command 'backward-delete-char-untabify))
        (equal (buffer-substring (- company-point (length company-prefix))
                                 company-point)
               company-prefix)))

commit 49ff650f0b1178a3e7d0e4e9fb83b13d3eaf9d8d
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 18 18:19:37 2009 +0200

    Added safer posn-col-row workaround.

diff --git a/company.el b/company.el
index 9233d57..64c7bc9 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added safer workaround for Emacs `posn-col-row' bug.
+;;
 ;; 2009-04-18 (0.4)
 ;;    Automatic completion is now aborted if the prefix gets too short.
 ;;    Added option `company-dabbrev-time-limit'.
@@ -576,6 +578,18 @@ keymap during active completions (`company-active-map'):
 (defun company-input-noop ()
   (push 31415926 unread-command-events))
 
+;; Hack:
+;; posn-col-row is incorrect in older Emacsen when line-spacing is set
+(defun company--col-row (&optional pos)
+  (let ((posn (posn-at-point pos)))
+    (cons (car (posn-col-row posn)) (cdr (posn-actual-col-row posn)))))
+
+(defsubst company--column (&optional pos)
+  (car (posn-col-row (posn-at-point pos))))
+
+(defsubst company--row (&optional pos)
+  (cdr (posn-actual-col-row (posn-at-point pos))))
+
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun company-grab (regexp &optional expression limit)
@@ -1203,7 +1217,7 @@ followed by `company-search-kill-others' after each 
input."
   (interactive "e")
   (when (nth 4 (event-start event))
     (company-set-selection (- (cdr (posn-actual-col-row (event-start event)))
-                              (cdr (posn-actual-col-row (posn-at-point)))
+                              (company--row)
                               1))
     t))
 
@@ -1296,7 +1310,7 @@ To show the number next to the candidates in some 
back-ends, enable
   `(when (company-manual-begin)
      (save-window-excursion
        (let ((height (window-height))
-             (row (cdr (posn-actual-col-row (posn-at-point)))))
+             (row (company--row)))
          ,@body
          (and (< (window-height) height)
               (< (- (window-height) row 2) company-tooltip-limit)
@@ -1464,7 +1478,7 @@ Example:
 
 (defun company-buffer-lines (beg end)
   (goto-char beg)
-  (let ((row (cdr (posn-actual-col-row (posn-at-point))))
+  (let ((row (company--row))
         lines)
     (while (and (equal (move-to-window-line (incf row)) row)
                 (<= (point) end))
@@ -1589,7 +1603,7 @@ Example:
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
-  (let ((col-row (posn-actual-col-row (posn-at-point pos))))
+  (let ((col-row (company--col-row pos)))
     (when col-row
       (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
                                    company-selection))))

commit 8089ffc6c5a6519c310362753071f9aa84a0e46b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 18 00:01:52 2009 +0200

    Bumped version to 0.4.

diff --git a/company-abbrev.el b/company-abbrev.el
index 7a6d6ec..0394e10 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index 2e972a6..720a459 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 0f0ac57..b0ca8f9 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 212a430..3a686b9 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index b75fcd8..486f4fe 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index 07cd0f5..3df6963 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 2d60cee..9f5fb1d 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 146cb12..754b3eb 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index 8602745..bf632d3 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-keywords.el b/company-keywords.el
index df42aaa..4bddd83 100644
--- a/company-keywords.el
+++ b/company-keywords.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 06ad0bc..6ee2cc6 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 19ba24b..92f790f 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index 29ba893..4d23bf6 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index 483db6a..b3e6261 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 58db9e4..5e7b813 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.1.
+;; This file is part of company 0.4.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index 5a43fe0..9233d57 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.3.1
+;; Version: 0.4
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-18 (0.4)
 ;;    Automatic completion is now aborted if the prefix gets too short.
 ;;    Added option `company-dabbrev-time-limit'.
 ;;    `company-backends' now supports merging back-ends.

commit 07f94a47fa2f5c607b920226ab675baac245bb4c
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 18 11:44:55 2009 +0200

    Added company-keywords back-end.

diff --git a/company-keywords.el b/company-keywords.el
new file mode 100644
index 0000000..df42aaa
--- /dev/null
+++ b/company-keywords.el
@@ -0,0 +1,162 @@
+;;; company-keywords.el --- a company back-end for programming language 
keywords
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.3.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defvar company-keywords-alist
+  ;; Please contribute corrections or additions.
+  '((c++-mode
+     "asm" "auto" "bool" "break" "case" "catch" "char" "class" "const"
+     "const_cast" "continue" "default" "delete" "do" "double" "dynamic_cast"
+     "else" "enum" "explicit" "export" "extern" "false" "float" "for" "friend"
+     "goto" "if" "inline" "int" "long" "mutable" "namespace" "new"
+     "operator" "private" "protected" "public" "register" "reinterpret_cast"
+     "return" "short" "signed" "sizeof" "static" "static_cast" "struct" 
"switch"
+     "template" "this" "throw" "true" "try" "typedef" "typeid" "typename"
+     "union" "unsigned" "using" "virtual" "void" "volatile" "wchar_t" "while")
+    (c-mode
+     "auto" "break" "case" "char" "const" "continue" "default" "do"
+     "double" "else" "enum" "extern" "float" "for" "goto" "if" "int" "long"
+     "register" "return" "short" "signed" "sizeof" "static" "struct"
+     "switch" "typedef" "union" "unsigned" "void" "volatile" "while")
+    (csharp-mode
+     "abstract" "add" "alias" "as" "base" "bool" "break" "byte" "case"
+     "catch" "char" "checked" "class" "const" "continue" "decimal" "default"
+     "delegate" "do" "double" "else" "enum" "event" "explicit" "extern"
+     "false" "finally" "fixed" "float" "for" "foreach" "get" "global" "goto"
+     "if" "implicit" "in" "int" "interface" "internal" "is" "lock" "long"
+     "namespace" "new" "null" "object" "operator" "out" "override" "params"
+     "partial" "private" "protected" "public" "readonly" "ref" "remove"
+     "return" "sbyte" "sealed" "set" "short" "sizeof" "stackalloc" "static"
+     "string" "struct" "switch" "this" "throw" "true" "try" "typeof" "uint"
+     "ulong" "unchecked" "unsafe" "ushort" "using" "value" "var" "virtual"
+     "void" "volatile" "where" "while" "yield")
+    (d-mode
+     ;; from http://www.digitalmars.com/d/2.0/lex.html
+     "abstract" "alias" "align" "asm"
+     "assert" "auto" "body" "bool" "break" "byte" "case" "cast" "catch"
+     "cdouble" "cent" "cfloat" "char" "class" "const" "continue" "creal"
+     "dchar" "debug" "default" "delegate" "delete" "deprecated" "do"
+     "double" "else" "enum" "export" "extern" "false" "final" "finally"
+     "float" "for" "foreach" "foreach_reverse" "function" "goto" "idouble"
+     "if" "ifloat" "import" "in" "inout" "int" "interface" "invariant"
+     "ireal" "is" "lazy" "long" "macro" "mixin" "module" "new" "nothrow"
+     "null" "out" "override" "package" "pragma" "private" "protected"
+     "public" "pure" "real" "ref" "return" "scope" "short" "static" "struct"
+     "super" "switch" "synchronized" "template" "this" "throw" "true" "try"
+     "typedef" "typeid" "typeof" "ubyte" "ucent" "uint" "ulong" "union"
+     "unittest" "ushort" "version" "void" "volatile" "wchar" "while" "with")
+    (java-mode
+     "abstract" "assert" "boolean" "break" "byte" "case" "catch" "char" "class"
+     "continue" "default" "do" "double" "else" "enum" "extends" "final"
+     "finally" "float" "for" "if" "implements" "import" "instanceof" "int"
+     "interface" "long" "native" "new" "package" "private" "protected" "public"
+     "return" "short" "static" "strictfp" "super" "switch" "synchronized"
+     "this" "throw" "throws" "transient" "try" "void" "volatile" "while")
+    (javascript-mode
+     "break" "catch" "const" "continue" "delete" "do" "else" "export" "for"
+     "function" "if" "import" "in" "instanceOf" "label" "let" "new" "return"
+     "switch" "this" "throw" "try" "typeof" "var" "void" "while" "with" 
"yield")
+    (objc-mode
+     "@catch" "@class" "@encode" "@end" "@finally" "@implementation"
+     "@interface" "@private" "@protected" "@protocol" "@public"
+     "@selector" "@synchronized" "@throw" "@try" "alloc" "autorelease"
+     "bycopy" "byref" "in" "inout" "oneway" "out" "release" "retain")
+    (perl-mode
+     ;; from cperl.el
+     "AUTOLOAD" "BEGIN" "CHECK" "CORE" "DESTROY" "END" "INIT" "__END__"
+     "__FILE__" "__LINE__" "abs" "accept" "alarm" "and" "atan2" "bind"
+     "binmode" "bless" "caller" "chdir" "chmod" "chomp" "chop" "chown" "chr"
+     "chroot" "close" "closedir" "cmp" "connect" "continue" "cos"
+     "crypt" "dbmclose" "dbmopen" "defined" "delete" "die" "do" "dump" "each"
+     "else" "elsif" "endgrent" "endhostent" "endnetent" "endprotoent"
+     "endpwent" "endservent" "eof" "eq" "eval" "exec" "exists" "exit" "exp"
+     "fcntl" "fileno" "flock" "for" "foreach" "fork" "format" "formline"
+     "ge" "getc" "getgrent" "getgrgid" "getgrnam" "gethostbyaddr"
+     "gethostbyname" "gethostent" "getlogin" "getnetbyaddr" "getnetbyname"
+     "getnetent" "getpeername" "getpgrp" "getppid" "getpriority"
+     "getprotobyname" "getprotobynumber" "getprotoent" "getpwent" "getpwnam"
+     "getpwuid" "getservbyname" "getservbyport" "getservent" "getsockname"
+     "getsockopt" "glob" "gmtime" "goto" "grep" "gt" "hex" "if" "index" "int"
+     "ioctl" "join" "keys" "kill" "last" "lc" "lcfirst" "le" "length"
+     "link" "listen" "local" "localtime" "lock" "log" "lstat" "lt" "map"
+     "mkdir" "msgctl" "msgget" "msgrcv" "msgsnd" "my" "ne" "next" "no"
+     "not" "oct" "open" "opendir" "or" "ord" "our" "pack" "package" "pipe"
+     "pop" "pos" "print" "printf" "push" "q" "qq" "quotemeta" "qw" "qx"
+     "rand" "read" "readdir" "readline" "readlink" "readpipe" "recv" "redo"
+     "ref" "rename" "require" "reset" "return" "reverse" "rewinddir" "rindex"
+     "rmdir" "scalar" "seek" "seekdir" "select" "semctl" "semget" "semop"
+     "send" "setgrent" "sethostent" "setnetent" "setpgrp" "setpriority"
+     "setprotoent" "setpwent" "setservent" "setsockopt" "shift" "shmctl"
+     "shmget" "shmread" "shmwrite" "shutdown" "sin" "sleep" "socket"
+     "socketpair" "sort" "splice" "split" "sprintf" "sqrt" "srand" "stat"
+     "study" "sub" "substr" "symlink" "syscall" "sysopen" "sysread" "system"
+     "syswrite" "tell" "telldir" "tie" "time" "times" "tr" "truncate" "uc"
+     "ucfirst" "umask" "undef" "unless" "unlink" "unpack" "unshift" "untie"
+     "until" "use" "utime" "values" "vec" "wait" "waitpid"
+     "wantarray" "warn" "while" "write" "x" "xor" "y")
+    (php-mode
+     "__CLASS__" "__DIR__" "__FILE__" "__FUNCTION__" "__LINE__" "__METHOD__"
+     "__NAMESPACE__" "_once" "abstract" "and" "array" "as" "break" "case"
+     "catch" "cfunction" "class" "clone" "const" "continue" "declare"
+     "default" "die" "do" "echo" "else" "elseif" "empty" "enddeclare"
+     "endfor" "endforeach" "endif" "endswitch" "endwhile" "eval" "exception"
+     "exit" "extends" "final" "for" "foreach" "function" "global"
+     "goto" "if" "implements" "include" "instanceof" "interface"
+     "isset" "list" "namespace" "new" "old_function" "or" "php_user_filter"
+     "print" "private" "protected" "public" "require" "require_once" "return"
+     "static" "switch" "this" "throw" "try" "unset" "use" "var" "while" "xor")
+    (python-mode
+     "and" "assert" "break" "class" "continue" "def" "del" "elif" "else"
+     "except" "exec" "finally" "for" "from" "global" "if" "import" "in" "is"
+     "lambda" "not" "or" "pass" "print" "raise" "return" "try" "while" "yield")
+    (ruby-mode
+     "BEGIN" "END" "alias" "and"  "begin" "break" "case" "class" "def" 
"defined"
+     "do" "else" "elsif"  "end" "ensure" "false" "for" "if" "in" "module"
+     "next" "nil" "not" "or" "redo" "rescue" "retry" "return" "self" "super"
+     "then" "true" "undef" "unless" "until" "when" "while" "yield")
+    ;; aliases
+    (js2-mode . javascript-mode)
+    (espresso-mode . javascript-mode)
+    (cperl-mode . perl-mode)
+    (jde-mode . java-mode))
+  "*Alist mapping major-modes to sorted keywords for `company-keywords'.")
+
+;;;###autoload
+(defun company-keywords (command &optional arg &rest ignored)
+  "A `company-mode' back-end for programming language keywords."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-))
+    ('prefix (and (assq major-mode company-keywords-alist)
+                  (not (company-in-string-or-comment))
+                  (or (company-grab-symbol) 'stop)))
+    ('candidates
+     (let ((case-fold-search nil)
+           (symbols (cdr (assq major-mode company-keywords-alist))))
+       (all-completions arg (if (consp symbols)
+                                symbols
+                              (cdr (assq symbols company-keywords-alist))))))
+    ('sorted t)))
+
+(provide 'company-keywords)
+;;; company-keywords.el ends here
+
+
diff --git a/company.el b/company.el
index f600bcb..5a43fe0 100644
--- a/company.el
+++ b/company.el
@@ -256,6 +256,7 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
     (company-files . "Files")
     (company-gtags . "GNU Global")
     (company-ispell . "ispell")
+    (company-keywords . "Programming language keywords")
     (company-nxml . "nxml")
     (company-oddmuse . "Oddmuse")
     (company-semantic . "CEDET Semantic")
@@ -273,7 +274,8 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
 
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-xcode
-                              (company-gtags company-etags 
company-dabbrev-code)
+                              (company-gtags company-etags company-dabbrev-code
+                               company-keywords)
                               company-oddmuse company-files company-dabbrev)
   "*The list of active back-ends (completion engines).
 Each list elements can itself be a list of back-ends.  In that case their

commit 267cd4701eed4f7286a9953f4837807c4be3f13a
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 21:04:38 2009 +0200

    Try not to prompt for TAGS file.

diff --git a/company-etags.el b/company-etags.el
index 321f4f8..07cd0f5 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -66,7 +66,9 @@ buffer automatically."
                   (or (company-grab-symbol) 'stop)))
     ('candidates (let ((tags-table-list (company-etags-buffer-table))
                        (completion-ignore-case nil))
-                   (and (fboundp 'tags-completion-table)
+                   (and (or tags-file-name tags-table-list)
+                        (fboundp 'tags-completion-table)
+                        tags-table-list
                         (all-completions arg (tags-completion-table)))))
     ('location (let ((tags-table-list (company-etags-buffer-table)))
                  (when (fboundp 'find-tag-noselect)

commit ecc1e5c52975b654ce934e7077cad0b92b9c566b
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 20:50:40 2009 +0200

    Don't use Xcode back-end if not in a project directory.

diff --git a/company-xcode.el b/company-xcode.el
index d221d79..58db9e4 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -100,6 +100,7 @@ valid in most contexts."
   (case command
     ('interactive (company-begin-backend 'company-xcode))
     ('prefix (and company-xcode-xcodeindex-executable
+                  (company-xcode-tags)
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
     ('candidates (let ((completion-ignore-case nil))

commit e4f5461b3c0c4c7376a532762bc50d38b5456971
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 14:58:28 2009 +0200

    Starting no longer interrupts commands that depend on last-command.
    
    For example, yank-pop didn't work if the timer fired since yank.

diff --git a/company.el b/company.el
index b190111..f600bcb 100644
--- a/company.el
+++ b/company.el
@@ -565,7 +565,8 @@ keymap during active completions (`company-active-map'):
 ;; Emacs calculates the active keymaps before reading the event.  That means we
 ;; cannot change the keymap from a timer.  So we send a bogus command.
 (defun company-ignore ()
-  (interactive))
+  (interactive)
+  (setq this-command last-command))
 
 (global-set-key '[31415926] 'company-ignore)
 

commit d80571561d5b27eb7b486757a42ceb8348c15f1f
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 14:38:18 2009 +0200

    Extracted company--begin-new.

diff --git a/company.el b/company.el
index 5c2b840..b190111 100644
--- a/company.el
+++ b/company.el
@@ -872,36 +872,37 @@ keymap during active completions (`company-active-map'):
       c)
      (t (company--continue-failed new-prefix)))))
 
+(defun company--begin-new ()
+  (let (prefix c)
+    (dolist (backend (if company-backend
+                         ;; prefer manual override
+                         (list company-backend)
+                       company-backends))
+      (setq prefix
+            (if (or (symbolp backend)
+                    (functionp backend))
+                (when (or (not (symbolp backend))
+                          (get backend 'company-init))
+                  (funcall backend 'prefix))
+              (company--multi-backend-adapter backend 'prefix)))
+      (when prefix
+        (when (and (stringp prefix)
+                   (>= (length prefix) company-minimum-prefix-length))
+          (setq company-backend backend
+                company-prefix prefix
+                c (company-calculate-candidates prefix))
+          ;; t means complete/unique.  We don't start, so no hooks.
+          (when (consp c)
+            (company-update-candidates c)
+            (run-hook-with-args 'company-completion-started-hook
+                                (company-explicit-action-p))
+            (company-call-frontends 'show)))
+        (return c)))))
+
 (defun company-begin ()
-  (when company-candidates
-    (setq company-candidates (company--continue)))
-  (when (and (not company-candidates)
-             (company--should-complete))
-    (let (prefix)
-      (dolist (backend (if company-backend
-                           ;; prefer manual override
-                           (list company-backend)
-                         company-backends))
-        (setq prefix
-              (if (or (symbolp backend)
-                      (functionp backend))
-                  (when (or (not (symbolp backend))
-                            (get backend 'company-init))
-                    (funcall backend 'prefix))
-                (company--multi-backend-adapter backend 'prefix)))
-        (when prefix
-          (when (and (stringp prefix)
-                     (>= (length prefix) company-minimum-prefix-length))
-            (setq company-backend backend
-                  company-prefix prefix)
-            (let ((c (company-calculate-candidates prefix)))
-              ;; t means complete/unique.  We don't start, so no hooks.
-              (when (consp c)
-                (company-update-candidates c)
-                (run-hook-with-args 'company-completion-started-hook
-                                    (company-explicit-action-p))
-                (company-call-frontends 'show))))
-          (return prefix)))))
+  (setq company-candidates
+        (or (and company-candidates (company--continue))
+            (and (company--should-complete) (company--begin-new))))
   (if company-candidates
       (progn
         (when (and company-end-of-buffer-workaround (eobp))

commit 41b7e4f0a6ed36537ec424f7179d28a6ad1deb9c
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 14:23:39 2009 +0200

    Refactored company-continue.

diff --git a/company.el b/company.el
index aed6686..5c2b840 100644
--- a/company.el
+++ b/company.el
@@ -791,10 +791,6 @@ keymap during active completions (`company-active-map'):
   ;; Return non-nil if active.
   company-candidates)
 
-(defsubst company-incremental-p (old-prefix new-prefix)
-  (and (> (length new-prefix) (length old-prefix))
-       (equal old-prefix (substring new-prefix 0 (length old-prefix)))))
-
 (defun company-require-match-p ()
   (let ((backend-value (company-call-backend 'require-match)))
     (or (eq backend-value t)
@@ -807,59 +803,79 @@ keymap during active completions (`company-active-map'):
   "Return non-nil, if input starts with punctuation or parentheses."
   (memq (char-syntax (string-to-char input)) '(?. ?\( ?\))))
 
-(defun company-auto-complete-p (beg end)
+(defun company-auto-complete-p (input)
   "Return non-nil, if input starts with punctuation or parentheses."
-  (and (> end beg)
-       ;; Make sure something was inserted, and we didn't just move forward.
-       (> (point-max) company--point-max)
-       (if (functionp company-auto-complete)
+  (and (if (functionp company-auto-complete)
            (funcall company-auto-complete)
          company-auto-complete)
        (if (functionp company-auto-complete-chars)
-           (funcall company-auto-complete-chars (buffer-substring beg end))
+           (funcall company-auto-complete-chars input)
          (if (consp company-auto-complete-chars)
-             (memq (char-syntax (char-after beg)) company-auto-complete-chars)
-           (string-match (buffer-substring beg (1+ beg))
-                         company-auto-complete-chars)))))
+             (memq (char-syntax (string-to-char input))
+                   company-auto-complete-chars)
+           (string-match (substring input 0 1) company-auto-complete-chars)))))
 
-(defun company-continue ()
+(defun company--incremental-p ()
+  (and (> (point) company-point)
+       (> (point-max) company--point-max)
+       (equal (buffer-substring (- company-point (length company-prefix))
+                                company-point)
+              company-prefix)))
+
+(defsubst company--string-incremental-p (old-prefix new-prefix)
+  (and (> (length new-prefix) (length old-prefix))
+       (equal old-prefix (substring new-prefix 0 (length old-prefix)))))
+
+(defun company--continue-failed (new-prefix)
+  (when (company--incremental-p)
+    (let ((input (buffer-substring-no-properties (point) company-point)))
+      (cond
+       ((company-auto-complete-p input)
+        ;; auto-complete
+        (save-excursion
+          (goto-char company-point)
+          (company-complete-selection)
+          nil))
+       ((and (company--string-incremental-p company-prefix new-prefix)
+             (company-require-match-p))
+        ;; wrong incremental input, but required match
+        (backward-delete-char (length input))
+        (ding)
+        (message "Matching input is required")
+        company-candidates)
+       ((equal company-prefix (car company-candidates))
+        ;; last input was actually success
+        (company-cancel company-prefix)
+        nil)))))
+
+(defun company--continue ()
   (when (company-call-backend 'no-cache company-prefix)
     ;; Don't complete existing candidates, fetch new ones.
     (setq company-candidates-cache nil))
-  (let ((new-prefix (company-call-backend 'prefix)))
-    (if (and (or (company-explicit-action-p)
-                 (>= (length new-prefix) company-minimum-prefix-length))
-             (= (- (point) (length new-prefix))
-                (- company-point (length company-prefix))))
-        (unless (or (equal company-prefix new-prefix)
-                    (let ((c (company-calculate-candidates new-prefix)))
-                      ;; t means complete/unique.
-                      (if (eq c t)
-                          (progn (company-cancel new-prefix) t)
-                        (when (consp c)
-                          (setq company-prefix new-prefix)
-                          (company-update-candidates c)
-                          t))))
-          (if (not (and (company-incremental-p company-prefix new-prefix)
-                        (company-require-match-p)))
-              (progn
-                (when (equal company-prefix (car company-candidates))
-                  ;; cancel, but last input was actually success
-                  (company-cancel company-prefix))
-                (setq company-candidates nil))
-            (backward-delete-char (length new-prefix))
-            (insert company-prefix)
-            (ding)
-            (message "Matching input is required")))
-      (when (company-auto-complete-p company-point (point))
-        (save-excursion
-          (goto-char company-point)
-          (company-complete-selection)))
-      (setq company-candidates nil))
-    company-candidates))
+  (let* ((new-prefix (company-call-backend 'prefix))
+         (c (when (and (stringp new-prefix)
+                       (or (company-explicit-action-p)
+                           (>= (length new-prefix)
+                               company-minimum-prefix-length))
+                       (= (- (point) (length new-prefix))
+                          (- company-point (length company-prefix))))
+              (company-calculate-candidates new-prefix))))
+    (cond
+     ((eq c t)
+      ;; t means complete/unique.
+      (company-cancel new-prefix)
+      nil)
+     ((consp c)
+      ;; incremental match
+      (setq company-prefix new-prefix)
+      (company-update-candidates c)
+      c)
+     (t (company--continue-failed new-prefix)))))
 
 (defun company-begin ()
-  (when (and (not (and company-candidates (company-continue)))
+  (when company-candidates
+    (setq company-candidates (company--continue)))
+  (when (and (not company-candidates)
              (company--should-complete))
     (let (prefix)
       (dolist (backend (if company-backend

commit fd0e01d6aee77a5f2abe7449c66a8de225e7c46e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 23:07:20 2009 +0200

    Abort automatic completion if the prefix gets too short.

diff --git a/company.el b/company.el
index 52c9e26..aed6686 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Automatic completion is now aborted if the prefix gets too short.
 ;;    Added option `company-dabbrev-time-limit'.
 ;;    `company-backends' now supports merging back-ends.
 ;;    Added back-end `company-dabbrev-code' for generic code.
@@ -826,8 +827,10 @@ keymap during active completions (`company-active-map'):
     ;; Don't complete existing candidates, fetch new ones.
     (setq company-candidates-cache nil))
   (let ((new-prefix (company-call-backend 'prefix)))
-    (if (= (- (point) (length new-prefix))
-           (- company-point (length company-prefix)))
+    (if (and (or (company-explicit-action-p)
+                 (>= (length new-prefix) company-minimum-prefix-length))
+             (= (- (point) (length new-prefix))
+                (- company-point (length company-prefix))))
         (unless (or (equal company-prefix new-prefix)
                     (let ((c (company-calculate-candidates new-prefix)))
                       ;; t means complete/unique.

commit ab726bc047ace6c9808bd6329100b411091dfc5e
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 11:42:50 2009 +0200

    Don't auto-complete when moving char forward.

diff --git a/company.el b/company.el
index df2c648..52c9e26 100644
--- a/company.el
+++ b/company.el
@@ -651,6 +651,9 @@ keymap during active completions (`company-active-map'):
   "Non-nil, if explicit completion took place.")
 (make-variable-buffer-local 'company--explicit-action)
 
+(defvar company--point-max nil)
+(make-variable-buffer-local 'company--point-max)
+
 (defvar company--this-command nil)
 
 (defvar company-point nil)
@@ -806,6 +809,8 @@ keymap during active completions (`company-active-map'):
 (defun company-auto-complete-p (beg end)
   "Return non-nil, if input starts with punctuation or parentheses."
   (and (> end beg)
+       ;; Make sure something was inserted, and we didn't just move forward.
+       (> (point-max) company--point-max)
        (if (functionp company-auto-complete)
            (funcall company-auto-complete)
          company-auto-complete)
@@ -883,7 +888,8 @@ keymap during active completions (`company-active-map'):
         (when (and company-end-of-buffer-workaround (eobp))
           (save-excursion (insert "\n"))
           (setq company-added-newline (buffer-chars-modified-tick)))
-        (setq company-point (point))
+        (setq company-point (point)
+              company--point-max (point-max))
         (company-enable-overriding-keymap company-active-map)
         (company-call-frontends 'update))
     (company-cancel)))
@@ -911,6 +917,7 @@ keymap during active completions (`company-active-map'):
         company-selection 0
         company-selection-changed nil
         company--explicit-action nil
+        company--point-max nil
         company-point nil)
   (when company-timer
     (cancel-timer company-timer))

commit 4c4a1b2269e08565590ee523540e142a767fe79e
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 11:29:32 2009 +0200

    Shortened company-begin-with code a bit.

diff --git a/company.el b/company.el
index b689778..df2c648 100644
--- a/company.el
+++ b/company.el
@@ -1343,18 +1343,17 @@ completes the input.
 
 Example:
 \(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
+  (setq company-begin-with-marker (copy-marker (point) t))
   (company-begin-backend
-   (let ((start (- (point) (or prefix-length 0))))
-     (setq company-begin-with-marker (copy-marker (point) t))
-     `(lambda (command &optional arg &rest ignored)
-        (cond
-         ((eq command 'prefix)
-          (when (equal (point) (marker-position company-begin-with-marker))
-            (buffer-substring ,start (point))))
-         ((eq command 'candidates)
-          (all-completions arg ',candidates))
-         ((eq command 'require-match)
-          ,require-match))))
+   `(lambda (command &optional arg &rest ignored)
+      (cond
+       ((eq command 'prefix)
+        (when (equal (point) (marker-position company-begin-with-marker))
+          (buffer-substring ,(- (point) (or prefix-length 0)) (point))))
+       ((eq command 'candidates)
+        (all-completions arg ',candidates))
+       ((eq command 'require-match)
+        ,require-match)))
    callback))
 
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

commit 2000ad879def1bcb21c69a54e80ea840ef7aa4e0
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 11:19:13 2009 +0200

    Removed CL case statement from lambda, because it needs CL at run-time.

diff --git a/company.el b/company.el
index e5c81dc..b689778 100644
--- a/company.el
+++ b/company.el
@@ -1347,12 +1347,14 @@ Example:
    (let ((start (- (point) (or prefix-length 0))))
      (setq company-begin-with-marker (copy-marker (point) t))
      `(lambda (command &optional arg &rest ignored)
-        (case command
-          ('prefix (when (equal (point)
-                                (marker-position company-begin-with-marker))
-                     (buffer-substring ,start (point))))
-          ('candidates (all-completions arg ',candidates))
-          ('require-match ,require-match))))
+        (cond
+         ((eq command 'prefix)
+          (when (equal (point) (marker-position company-begin-with-marker))
+            (buffer-substring ,start (point))))
+         ((eq command 'candidates)
+          (all-completions arg ',candidates))
+         ((eq command 'require-match)
+          ,require-match))))
    callback))
 
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

commit d57ca4e4cbbb2fb14f2ec6584f9e27712c3f8d85
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 11:04:20 2009 +0200

    Fixed when tooltip was too short to display number of remaining items.

diff --git a/company.el b/company.el
index 9be3848..e5c81dc 100644
--- a/company.el
+++ b/company.el
@@ -1481,7 +1481,7 @@ Example:
                       (setq remainder (format "...(%d)" remainder))))
 
     (decf selection company-tooltip-offset)
-    (setq width (min (length previous) (length remainder))
+    (setq width (max (length previous) (length remainder))
           lines (nthcdr company-tooltip-offset company-candidates)
           len (min limit len)
           lines-copy lines)

commit 1b316edbaedef08c97798d0d2bd1cc633a6e2d77
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 10:50:07 2009 +0200

    Added better custom choices for back-end.

diff --git a/company.el b/company.el
index 12ba452..9be3848 100644
--- a/company.el
+++ b/company.el
@@ -246,9 +246,20 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                          (function :tag "custom function" nil))))
 
 (defvar company-safe-backends
-  '(company-abbrev company-css company-dabbrev-code company-dabbrev
-    company-elisp company-etags company-files company-gtags company-ispell
-    company-nxml company-oddmuse company-semantic company-tempo company-xcode))
+  '((company-abbrev . "Abbrev")
+    (company-css . "CSS")
+    (company-dabbrev . "dabbrev for plain text")
+    (company-dabbrev-code . "dabbrev for code")
+    (company-elisp . "Emacs Lisp")
+    (company-etags . "etags")
+    (company-files . "Files")
+    (company-gtags . "GNU Global")
+    (company-ispell . "ispell")
+    (company-nxml . "nxml")
+    (company-oddmuse . "Oddmuse")
+    (company-semantic . "CEDET Semantic")
+    (company-tempo . "Tempo templates")
+    (company-xcode . "Xcode")))
 (put 'company-safe-backends 'risky-local-variable t)
 
 (defun company-safe-backends-p (backends)
@@ -256,7 +267,7 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
        (not (dolist (backend backends)
               (unless (if (consp backend)
                           (company-safe-backends-p backend)
-                        (memq backend company-safe-backends))
+                        (assq backend company-safe-backends))
                 (return t))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
@@ -312,9 +323,18 @@ The back-end should return nil for all commands it does 
not support or
 does not know about.  It should also be callable interactively and use
 `company-begin-backend' to start itself in that case."
   :group 'company
-  :type '(repeat (choice (symbol :tag "Back-end")
-                         (repeat :tag "Merge"
-                                 (symbol :tag "Back-end")))))
+  :type `(repeat
+          (choice
+           :tag "Back-end"
+           ,@(mapcar (lambda (b) `(const :tag ,(cdr b) ,(car b)))
+                     company-safe-backends)
+           (symbol :tag "User defined")
+           (repeat :tag "Merged Back-ends"
+                   (choice :tag "Back-end"
+                           ,@(mapcar (lambda (b)
+                                       `(const :tag ,(cdr b) ,(car b)))
+                                     company-safe-backends)
+                           (symbol :tag "User defined"))))))
 
 (put 'company-backends 'safe-local-variable 'company-safe-backend-p)
 

commit d064e611972d41a2cee84fecde071a5cb0b857a4
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 10:40:24 2009 +0200

    Added company-dabbrev-char-regexp.

diff --git a/company-dabbrev.el b/company-dabbrev.el
index 3d828a1..212a430 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -36,6 +36,11 @@ See also `company-dabbrev-time-limit'."
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
 
+(defcustom company-dabbrev-char-regexp "\\sw"
+  "*A regular expression matching the characters `company-dabbrev' looks for."
+  :group 'company
+  :type 'regexp)
+
 (defmacro company-dabrev--time-limit-while (test start limit &rest body)
   (declare (indent 3) (debug t))
   `(let ((company-time-limit-while-counter 0))
@@ -49,7 +54,10 @@ See also `company-dabbrev-time-limit'."
               (throw 'done 'company-time-out))))))
 
 (defsubst company-dabbrev--make-regexp (prefix)
-  (concat "\\<" (if (equal prefix "") "\\sw" (regexp-quote prefix)) 
"\\sw*\\>"))
+  (concat "\\<" (if (equal prefix "")
+              company-dabbrev-char-regexp
+            (regexp-quote prefix))
+          "\\(" company-dabbrev-char-regexp "\\)*\\>"))
 
 (defun company-dabbrev--search-buffer (regexp pos symbols start limit
                                        ignore-comments)

commit 2ebc2cd4a19116249921e9c5a17b5a675669c4af
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 10:27:37 2009 +0200

    Merged company-dabbrev and company-dabbrev-code.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 4a17e5d..0f0ac57 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -18,6 +18,7 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
+(require 'company-dabbrev)
 (eval-when-compile (require 'cl))
 
 (defcustom company-dabbrev-code-modes
@@ -51,64 +52,12 @@ See also `company-dabbrev-code-time-limit'."
   :type '(choice (const :tag "Off" nil)
                  (number :tag "Seconds")))
 
-(defmacro company-dabrev-code--time-limit-while (test start limit &rest body)
-  (declare (indent 3) (debug t))
-  `(let ((company-time-limit-while-counter 0))
-     (catch 'done
-       (while ,test
-         ,@body
-         (and ,limit
-              (eq (incf company-time-limit-while-counter) 25)
-              (setq company-time-limit-while-counter 0)
-              (> (float-time (time-since ,start)) ,limit)
-              (throw 'done 'company-time-out))))))
-
 (defsubst company-dabbrev-code--make-regexp (prefix)
   (concat "\\_<" (if (equal prefix "")
                      "\\([a-zA-Z]\\|\\s_\\)"
                    (regexp-quote prefix))
           "\\(\\sw\\|\\s_\\)*\\_>"))
 
-(defun company-dabbrev-code--buffer-symbols (regexp pos &optional symbols
-                                             start limit)
-  (save-excursion
-    (let (match)
-      (goto-char (if pos (1- pos) (point-min)))
-      ;; search before pos
-      (company-dabrev-code--time-limit-while (re-search-backward regexp nil t)
-          start limit
-        (setq match (match-string-no-properties 0))
-        (if (company-in-string-or-comment)
-            (re-search-backward "\\s<\\|\\s!\\|\\s\"\\|\\s|" nil t)
-          (push match symbols)))
-      (goto-char (or pos (point-min)))
-      ;; search after pos
-      (company-dabrev-code--time-limit-while (re-search-forward regexp nil t)
-          start limit
-        (setq match (match-string-no-properties 0))
-        (if (company-in-string-or-comment)
-            (re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
-          (push match symbols)))
-      symbols)))
-
-(defun company-dabbrev-code--symbols (regexp)
-  (let* ((start (current-time))
-         (limit company-dabbrev-code-time-limit)
-         (symbols (company-dabbrev-code--buffer-symbols regexp (point) nil
-                                                        start limit)))
-    (when company-dabbrev-code-other-buffers
-      (dolist (buffer (delq (current-buffer) (buffer-list)))
-        (and (or (eq company-dabbrev-code-other-buffers 'all)
-                 (eq (buffer-local-value 'major-mode buffer) major-mode))
-             (with-current-buffer buffer
-               (setq symbols
-                     (company-dabbrev-code--buffer-symbols regexp nil symbols
-                                                           start limit))))
-        (and limit
-             (> (float-time (time-since start)) limit)
-             (return))))
-    symbols))
-
 ;;;###autoload
 (defun company-dabbrev-code (command &optional arg &rest ignored)
   "A dabbrev-like `company-mode' back-end for code.
@@ -122,8 +71,10 @@ comments or strings."
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
     ('candidates (let ((case-fold-search nil))
-                   (company-dabbrev-code--symbols
-                    (company-dabbrev-code--make-regexp arg))))
+                   (company-dabbrev--search
+                    (company-dabbrev-code--make-regexp arg)
+                    company-dabbrev-code-time-limit
+                    company-dabbrev-code-other-buffers t)))
     ('duplicates t)))
 
 (provide 'company-dabbrev-code)
diff --git a/company-dabbrev.el b/company-dabbrev.el
index c0379ff..3d828a1 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -1,4 +1,4 @@
-;;; company-dabbrev.el --- a company-mode completion back-end for dabbrev
+;;; company-dabbrev.el --- a dabbrev-like company-mode completion back-end
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
@@ -18,28 +18,93 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(require 'dabbrev)
 (eval-when-compile (require 'cl))
 
-(defun company-grab-dabbrev-prefix ()
+(defcustom company-dabbrev-other-buffers 'all
+  "*Determines whether `company-dabbrev' should search other buffers.
+If 'all, search all other buffers.  If t, search buffers with the same
+major-mode.
+See also `company-dabbrev-time-limit'."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "Same major mode" t)
+                 (const :tag "All" all)))
+
+(defcustom company-dabbrev-time-limit .5
+  "*Determines how many seconds `company-dabbrev' should look for matches."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (number :tag "Seconds")))
+
+(defmacro company-dabrev--time-limit-while (test start limit &rest body)
+  (declare (indent 3) (debug t))
+  `(let ((company-time-limit-while-counter 0))
+     (catch 'done
+       (while ,test
+         ,@body
+         (and ,limit
+              (eq (incf company-time-limit-while-counter) 25)
+              (setq company-time-limit-while-counter 0)
+              (> (float-time (time-since ,start)) ,limit)
+              (throw 'done 'company-time-out))))))
+
+(defsubst company-dabbrev--make-regexp (prefix)
+  (concat "\\<" (if (equal prefix "") "\\sw" (regexp-quote prefix)) 
"\\sw*\\>"))
+
+(defun company-dabbrev--search-buffer (regexp pos symbols start limit
+                                       ignore-comments)
   (save-excursion
-    (when (looking-at "\\>")
-      (let ((end (point)))
-        (dabbrev--reset-global-variables)
-        (dabbrev--goto-start-of-abbrev)
-        (buffer-substring-no-properties (point) end)))))
+    (let (match)
+      (goto-char (if pos (1- pos) (point-min)))
+      ;; search before pos
+      (company-dabrev--time-limit-while (re-search-backward regexp nil t)
+          start limit
+        (setq match (match-string-no-properties 0))
+        (if (and ignore-comments (company-in-string-or-comment))
+            (re-search-backward "\\s<\\|\\s!\\|\\s\"\\|\\s|" nil t)
+          (push match symbols)))
+      (goto-char (or pos (point-min)))
+      ;; search after pos
+      (company-dabrev--time-limit-while (re-search-forward regexp nil t)
+          start limit
+        (setq match (match-string-no-properties 0))
+        (if (and ignore-comments (company-in-string-or-comment))
+            (re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
+          (push match symbols)))
+      symbols)))
+
+(defun company-dabbrev--search (regexp &optional limit other-buffers
+                                ignore-comments)
+  (let* ((start (current-time))
+         (symbols (company-dabbrev--search-buffer regexp (point) nil start 
limit
+                                                  ignore-comments)))
+    (when other-buffers
+      (dolist (buffer (delq (current-buffer) (buffer-list)))
+        (and (or (eq other-buffers 'all)
+                 (eq (buffer-local-value 'major-mode buffer) major-mode))
+             (with-current-buffer buffer
+               (setq symbols
+                     (company-dabbrev--search-buffer regexp nil symbols start
+                                                     limit ignore-comments))))
+        (and limit
+             (> (float-time (time-since start)) limit)
+             (return))))
+    symbols))
 
 ;;;###autoload
 (defun company-dabbrev (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `dabbrev-completion'."
+  "A dabbrev-like `company-mode' completion back-end."
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-dabbrev))
-    ('prefix (company-grab-dabbrev-prefix))
-    ('candidates (let ((dabbrev-check-other-buffers))
-                   (dabbrev--reset-global-variables)
-                   (dabbrev--find-all-expansions arg t)))
-    ('ignore-case t)))
+    ('prefix (company-grab-word))
+    ('candidates
+     (mapcar 'downcase
+             (company-dabbrev--search (company-dabbrev--make-regexp arg)
+                                      company-dabbrev-time-limit
+                                      company-dabbrev-other-buffers)))
+    ('ignore-case t)
+    ('duplicates t)))
 
 (provide 'company-dabbrev)
 ;;; company-dabbrev.el ends here
diff --git a/company.el b/company.el
index 66eddd7..12ba452 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added option `company-dabbrev-time-limit'.
 ;;    `company-backends' now supports merging back-ends.
 ;;    Added back-end `company-dabbrev-code' for generic code.
 ;;    Fixed `company-begin-with'.

commit 607dfa19ad9383f5b37643a6308593ea2893e574
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 10:02:58 2009 +0200

    Added dabbrev-code option to search all other buffers.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 0787e3d..4a17e5d 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -37,11 +37,13 @@ Value t means complete in all modes."
 
 (defcustom company-dabbrev-code-other-buffers t
   "*Determines whether `company-dabbrev-code' should search other buffers.
-If t, search all buffers with the same major-mode.
+If 'all, search all other buffers.  If t, search buffers with the same
+major-mode.
 See also `company-dabbrev-code-time-limit'."
   :group 'company
   :type '(choice (const :tag "Off" nil)
-                 (const :tag "Same major mode" t)))
+                 (const :tag "Same major mode" t)
+                 (const :tag "All" all)))
 
 (defcustom company-dabbrev-code-time-limit .5
   "*Determines how long `company-dabbrev-code' should look for matches."
@@ -96,7 +98,8 @@ See also `company-dabbrev-code-time-limit'."
                                                         start limit)))
     (when company-dabbrev-code-other-buffers
       (dolist (buffer (delq (current-buffer) (buffer-list)))
-        (and (eq (buffer-local-value 'major-mode buffer) major-mode)
+        (and (or (eq company-dabbrev-code-other-buffers 'all)
+                 (eq (buffer-local-value 'major-mode buffer) major-mode))
              (with-current-buffer buffer
                (setq symbols
                      (company-dabbrev-code--buffer-symbols regexp nil symbols

commit acb0ac5eb7b0ffd1a674156145a5e1c45d4ae58e
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 09:54:02 2009 +0200

    Time-limit dabbrev-code search in current buffer, too.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 1ca67e2..0787e3d 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -35,13 +35,18 @@ Value t means complete in all modes."
   :type '(choice (repeat (symbol :tag "Major mode"))
                  (const tag "All modes" t)))
 
-(defcustom company-dabbrev-code-other-buffers .5
+(defcustom company-dabbrev-code-other-buffers t
   "*Determines whether `company-dabbrev-code' should search other buffers.
-If t, search all buffers with the same major-mode.  A numeric value means
-search other buffers for that many seconds and then return."
+If t, search all buffers with the same major-mode.
+See also `company-dabbrev-code-time-limit'."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "Same major mode" t)))
+
+(defcustom company-dabbrev-code-time-limit .5
+  "*Determines how long `company-dabbrev-code' should look for matches."
   :group 'company
   :type '(choice (const :tag "Off" nil)
-                 (const :tag "Same major mode" t)
                  (number :tag "Seconds")))
 
 (defmacro company-dabrev-code--time-limit-while (test start limit &rest body)
@@ -65,29 +70,40 @@ search other buffers for that many seconds and then return."
 (defun company-dabbrev-code--buffer-symbols (regexp pos &optional symbols
                                              start limit)
   (save-excursion
-    (goto-char (point-min))
     (let (match)
+      (goto-char (if pos (1- pos) (point-min)))
+      ;; search before pos
+      (company-dabrev-code--time-limit-while (re-search-backward regexp nil t)
+          start limit
+        (setq match (match-string-no-properties 0))
+        (if (company-in-string-or-comment)
+            (re-search-backward "\\s<\\|\\s!\\|\\s\"\\|\\s|" nil t)
+          (push match symbols)))
+      (goto-char (or pos (point-min)))
+      ;; search after pos
       (company-dabrev-code--time-limit-while (re-search-forward regexp nil t)
           start limit
         (setq match (match-string-no-properties 0))
         (if (company-in-string-or-comment)
             (re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
-          (unless (eq (match-end 0) pos) ;; ignore match before point
-            (push match symbols))))
+          (push match symbols)))
       symbols)))
 
-(defun company-dabbrev-code--symbols (regexp &optional limit)
-  (let ((start (current-time))
-        (symbols (company-dabbrev-code--buffer-symbols regexp (point))))
-    (dolist (buffer (delq (current-buffer) (buffer-list)))
-      (and (eq (buffer-local-value 'major-mode buffer) major-mode)
-           (with-current-buffer buffer
-             (setq symbols
-                   (company-dabbrev-code--buffer-symbols regexp nil symbols
-                                                         start limit))))
-      (and limit
-           (> (float-time (time-since start)) limit)
-           (return)))
+(defun company-dabbrev-code--symbols (regexp)
+  (let* ((start (current-time))
+         (limit company-dabbrev-code-time-limit)
+         (symbols (company-dabbrev-code--buffer-symbols regexp (point) nil
+                                                        start limit)))
+    (when company-dabbrev-code-other-buffers
+      (dolist (buffer (delq (current-buffer) (buffer-list)))
+        (and (eq (buffer-local-value 'major-mode buffer) major-mode)
+             (with-current-buffer buffer
+               (setq symbols
+                     (company-dabbrev-code--buffer-symbols regexp nil symbols
+                                                           start limit))))
+        (and limit
+             (> (float-time (time-since start)) limit)
+             (return))))
     symbols))
 
 ;;;###autoload
@@ -102,14 +118,9 @@ comments or strings."
                       (apply 'derived-mode-p company-dabbrev-code-modes))
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((case-fold-search nil)
-                       (regexp (company-dabbrev-code--make-regexp prefix)))
-                   (if company-dabbrev-code-other-buffers
-                       (company-dabbrev-code--symbols
-                        arg
-                        (when (numberp company-dabbrev-code-other-buffers)
-                          company-dabbrev-code-other-buffers))
-                     (company-dabbrev-code--buffer-symbols arg (point)))))
+    ('candidates (let ((case-fold-search nil))
+                   (company-dabbrev-code--symbols
+                    (company-dabbrev-code--make-regexp arg))))
     ('duplicates t)))
 
 (provide 'company-dabbrev-code)

commit 7584ed95ed7da7c0d1d39308a0f765cd7a5a450a
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 09:25:38 2009 +0200

    Calculate dabbrev-code regexp earlier.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index b47aed5..1ca67e2 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -62,12 +62,11 @@ search other buffers for that many seconds and then return."
                    (regexp-quote prefix))
           "\\(\\sw\\|\\s_\\)*\\_>"))
 
-(defun company-dabbrev-code--buffer-symbols (prefix pos &optional symbols
+(defun company-dabbrev-code--buffer-symbols (regexp pos &optional symbols
                                              start limit)
   (save-excursion
     (goto-char (point-min))
-    (let ((regexp (company-dabbrev-code--make-regexp prefix))
-          match)
+    (let (match)
       (company-dabrev-code--time-limit-while (re-search-forward regexp nil t)
           start limit
         (setq match (match-string-no-properties 0))
@@ -77,14 +76,14 @@ search other buffers for that many seconds and then return."
             (push match symbols))))
       symbols)))
 
-(defun company-dabbrev-code--symbols (prefix &optional limit)
+(defun company-dabbrev-code--symbols (regexp &optional limit)
   (let ((start (current-time))
-        (symbols (company-dabbrev-code--buffer-symbols prefix (point))))
+        (symbols (company-dabbrev-code--buffer-symbols regexp (point))))
     (dolist (buffer (delq (current-buffer) (buffer-list)))
       (and (eq (buffer-local-value 'major-mode buffer) major-mode)
            (with-current-buffer buffer
              (setq symbols
-                   (company-dabbrev-code--buffer-symbols prefix nil symbols
+                   (company-dabbrev-code--buffer-symbols regexp nil symbols
                                                          start limit))))
       (and limit
            (> (float-time (time-since start)) limit)
@@ -103,7 +102,8 @@ comments or strings."
                       (apply 'derived-mode-p company-dabbrev-code-modes))
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
-    ('candidates (let ((case-fold-search nil))
+    ('candidates (let ((case-fold-search nil)
+                       (regexp (company-dabbrev-code--make-regexp prefix)))
                    (if company-dabbrev-code-other-buffers
                        (company-dabbrev-code--symbols
                         arg

commit 9875d164b8bae823ba50aa63ba2cb795fa45a45d
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 09:20:37 2009 +0200

    Extracted company-dabbrev-code--make-regexp.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 8f14a23..b47aed5 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -56,14 +56,17 @@ search other buffers for that many seconds and then return."
               (> (float-time (time-since ,start)) ,limit)
               (throw 'done 'company-time-out))))))
 
+(defsubst company-dabbrev-code--make-regexp (prefix)
+  (concat "\\_<" (if (equal prefix "")
+                     "\\([a-zA-Z]\\|\\s_\\)"
+                   (regexp-quote prefix))
+          "\\(\\sw\\|\\s_\\)*\\_>"))
+
 (defun company-dabbrev-code--buffer-symbols (prefix pos &optional symbols
                                              start limit)
   (save-excursion
     (goto-char (point-min))
-    (let ((regexp (concat "\\_<" (if (equal prefix "")
-                                     "\\([a-zA-Z]\\|\\s_\\)"
-                                   (regexp-quote prefix))
-                          "\\(\\sw\\|\\s_\\)*\\_>"))
+    (let ((regexp (company-dabbrev-code--make-regexp prefix))
           match)
       (company-dabrev-code--time-limit-while (re-search-forward regexp nil t)
           start limit

commit 1d2e611e871081adaab99944df01099ada1adbc1
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 17 09:18:07 2009 +0200

    Extracted company-dabrev-code--time-limit-while.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 31ffdd2..8f14a23 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -44,6 +44,18 @@ search other buffers for that many seconds and then return."
                  (const :tag "Same major mode" t)
                  (number :tag "Seconds")))
 
+(defmacro company-dabrev-code--time-limit-while (test start limit &rest body)
+  (declare (indent 3) (debug t))
+  `(let ((company-time-limit-while-counter 0))
+     (catch 'done
+       (while ,test
+         ,@body
+         (and ,limit
+              (eq (incf company-time-limit-while-counter) 25)
+              (setq company-time-limit-while-counter 0)
+              (> (float-time (time-since ,start)) ,limit)
+              (throw 'done 'company-time-out))))))
+
 (defun company-dabbrev-code--buffer-symbols (prefix pos &optional symbols
                                              start limit)
   (save-excursion
@@ -52,19 +64,14 @@ search other buffers for that many seconds and then return."
                                      "\\([a-zA-Z]\\|\\s_\\)"
                                    (regexp-quote prefix))
                           "\\(\\sw\\|\\s_\\)*\\_>"))
-          (i 0)
           match)
-      (while (re-search-forward regexp nil t)
+      (company-dabrev-code--time-limit-while (re-search-forward regexp nil t)
+          start limit
         (setq match (match-string-no-properties 0))
         (if (company-in-string-or-comment)
             (re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
           (unless (eq (match-end 0) pos) ;; ignore match before point
-            (push match symbols)))
-        (and limit
-             (eq (incf i) 25)
-             (setq i 0)
-             (> (float-time (time-since start)) limit)
-             (return symbols)))
+            (push match symbols))))
       symbols)))
 
 (defun company-dabbrev-code--symbols (prefix &optional limit)

commit 4efb1b0899a27905e55700f019b59835523de665
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 10:32:45 2009 +0200

    Added option to merge back-ends.

diff --git a/company.el b/company.el
index 4af3c5a..66eddd7 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    `company-backends' now supports merging back-ends.
 ;;    Added back-end `company-dabbrev-code' for generic code.
 ;;    Fixed `company-begin-with'.
 ;;
@@ -252,14 +253,20 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
 (defun company-safe-backends-p (backends)
   (and (consp backends)
        (not (dolist (backend backends)
-              (unless (memq backend company-safe-backends)
+              (unless (if (consp backend)
+                          (company-safe-backends-p backend)
+                        (memq backend company-safe-backends))
                 (return t))))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-xcode company-gtags
-                              company-etags company-oddmuse company-files
-                              company-dabbrev-code company-dabbrev)
+                              company-semantic company-xcode
+                              (company-gtags company-etags 
company-dabbrev-code)
+                              company-oddmuse company-files company-dabbrev)
   "*The list of active back-ends (completion engines).
+Each list elements can itself be a list of back-ends.  In that case their
+completions are merged.  Otherwise only the first matching back-end returns
+results.
+
 Each back-end is a function that takes a variable number of arguments.
 The first argument is the command requested from the back-end.  It is one
 of the following:
@@ -304,7 +311,9 @@ The back-end should return nil for all commands it does not 
support or
 does not know about.  It should also be callable interactively and use
 `company-begin-backend' to start itself in that case."
   :group 'company
-  :type '(repeat (function :tag "function" nil)))
+  :type '(repeat (choice (symbol :tag "Back-end")
+                         (repeat :tag "Merge"
+                                 (symbol :tag "Back-end")))))
 
 (put 'company-backends 'safe-local-variable 'company-safe-backend-p)
 
@@ -449,14 +458,17 @@ The work-around consists of adding a newline.")
   "Keymap that is enabled during an active completion.")
 
 (defun company-init-backend (backend)
-  (when (symbolp backend)
-    (unless (fboundp backend)
-      (ignore-errors (require backend nil t)))
-    (if (and (fboundp backend)
-             (ignore-errors (funcall backend 'init) t))
-        (put backend 'company-init t)
-      (message "Company back-end '%s' could not be initialized"
-               backend))))
+  (and (symbolp backend)
+       (not (fboundp backend))
+       (ignore-errors (require backend nil t)))
+
+  (if (or (symbolp backend)
+          (functionp backend))
+      (if (ignore-errors (funcall backend 'init) t)
+          (put backend 'company-init t)
+        (message "Company back-end '%s' could not be initialized"
+                 backend))
+    (mapc 'company-init-backend backend)))
 
 ;;;###autoload
 (define-minor-mode company-mode
@@ -568,7 +580,22 @@ keymap during active completions (`company-active-map'):
         (nth 3 ppss))))
 
 (defun company-call-backend (&rest args)
-  (apply 'company-backend args))
+  (if (functionp company-backend)
+      (apply company-backend args)
+    (apply 'company--multi-backend-adapter company-backend args)))
+
+(defun company--multi-backend-adapter (backends command &rest args)
+  (case command
+    ('candidates
+     (apply 'append (mapcar (lambda (backend) (apply backend command args))
+                            backends)))
+    ('sorted nil)
+    ('duplicates t)
+    (otherwise
+     (let (value)
+       (dolist (backend backends)
+         (when (setq value (apply backend command args))
+           (return value)))))))
 
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -810,9 +837,14 @@ keymap during active completions (`company-active-map'):
                            ;; prefer manual override
                            (list company-backend)
                          company-backends))
-        (when (and (get backend 'company-init)
-                   (functionp backend)
-                   (setq prefix (funcall backend 'prefix)))
+        (setq prefix
+              (if (or (symbolp backend)
+                      (functionp backend))
+                  (when (or (not (symbolp backend))
+                            (get backend 'company-init))
+                    (funcall backend 'prefix))
+                (company--multi-backend-adapter backend 'prefix)))
+        (when prefix
           (when (and (stringp prefix)
                      (>= (length prefix) company-minimum-prefix-length))
             (setq company-backend backend

commit a23b02a93a8ed14b726f3b1377439948ba343352
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 21:29:07 2009 +0200

    Small speed improvements to company-in-string-or-comment.

diff --git a/company.el b/company.el
index 65a35ed..4af3c5a 100644
--- a/company.el
+++ b/company.el
@@ -563,7 +563,9 @@ keymap during active completions (`company-active-map'):
 
 (defun company-in-string-or-comment ()
   (let ((ppss (syntax-ppss)))
-    (or (nth 3 ppss) (nth 4 ppss) (nth 7 ppss))))
+    (or (car (setq ppss (nthcdr 3 ppss)))
+        (car (setq ppss (cdr ppss)))
+        (nth 3 ppss))))
 
 (defun company-call-backend (&rest args)
   (apply 'company-backend args))

commit 8db19bcde085f3cdf3b98f84668f2ab1520dfab9
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 20:07:55 2009 +0200

    Added safe-local-variable predicate for company-backends.

diff --git a/company.el b/company.el
index 74dca39..65a35ed 100644
--- a/company.el
+++ b/company.el
@@ -243,6 +243,18 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
+(defvar company-safe-backends
+  '(company-abbrev company-css company-dabbrev-code company-dabbrev
+    company-elisp company-etags company-files company-gtags company-ispell
+    company-nxml company-oddmuse company-semantic company-tempo company-xcode))
+(put 'company-safe-backends 'risky-local-variable t)
+
+(defun company-safe-backends-p (backends)
+  (and (consp backends)
+       (not (dolist (backend backends)
+              (unless (memq backend company-safe-backends)
+                (return t))))))
+
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-xcode company-gtags
                               company-etags company-oddmuse company-files
@@ -294,6 +306,8 @@ does not know about.  It should also be callable 
interactively and use
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
+(put 'company-backends 'safe-local-variable 'company-safe-backend-p)
+
 (defcustom company-completion-started-hook nil
   "*Hook run when company starts completing.
 The hook is called with one argument that is non-nil if the completion was

commit 818af05a6814f51a463a8973d5efe94a21c006c4
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 17:40:39 2009 +0200

    Removed debugging code that lead to wrong configuration.

diff --git a/company-etags.el b/company-etags.el
index db6a1aa..321f4f8 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -74,9 +74,5 @@ buffer automatically."
                      (cons buffer (with-current-buffer buffer (point)))))))
     ('sorted t)))
 
-(add-to-list 'company-backends 'company-etags)
-
 (provide 'company-etags)
 ;;; company-etags.el ends here
-
-

commit 7f0b7a870248000e9527870cd1efd1fb4b31444f
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 17:10:34 2009 +0200

    Fixed 'stop location in elisp back-end.

diff --git a/company-elisp.el b/company-elisp.el
index bb08355..b75fcd8 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -30,9 +30,11 @@ Functions are offered for completion only after ' and \(."
 
 (defun company-grab-lisp-symbol ()
   (let ((prefix (company-grab-symbol)))
-    (unless (and (company-in-string-or-comment)
-                 (/= (char-before (- (point) (length prefix))) ?`))
-      prefix)))
+    (if prefix
+        (unless (and (company-in-string-or-comment)
+                     (/= (char-before (- (point) (length prefix))) ?`))
+          prefix)
+      'stop)))
 
 (defun company-elisp-predicate (symbol)
   (or (boundp symbol)
@@ -109,7 +111,7 @@ Functions are offered for completion only after ' and \(."
   (case command
     ('interactive (company-begin-backend 'company-elisp))
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
-                  (or (company-grab-lisp-symbol) 'stop)))
+                  (company-grab-lisp-symbol)))
     ('candidates (company-elisp-candidates arg))
     ('meta (company-elisp-doc arg))
     ('doc-buffer (let ((symbol (intern arg)))

commit 198ff61d2be54cc31eb09602a402f60f32549cc0
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 13:30:59 2009 +0200

    Prevent accidental auto-insert when moving point.

diff --git a/company.el b/company.el
index adb0d46..74dca39 100644
--- a/company.el
+++ b/company.el
@@ -757,34 +757,34 @@ keymap during active completions (`company-active-map'):
     ;; Don't complete existing candidates, fetch new ones.
     (setq company-candidates-cache nil))
   (let ((new-prefix (company-call-backend 'prefix)))
-    (unless (and (= (- (point) (length new-prefix))
-                    (- company-point (length company-prefix)))
-                 (or (equal company-prefix new-prefix)
-                     (let ((c (company-calculate-candidates new-prefix)))
-                       ;; t means complete/unique.
-                       (if (eq c t)
-                           (progn (company-cancel new-prefix) t)
-                         (when (consp c)
-                           (setq company-prefix new-prefix)
-                           (company-update-candidates c)
-                           t)))))
-      (if (company-auto-complete-p company-point (point))
-          (save-excursion
-            (goto-char company-point)
-            (company-complete-selection)
-            (setq company-candidates nil))
-        (if (not (and (company-incremental-p company-prefix new-prefix)
-                      (company-require-match-p)))
-            (progn
-              (when (equal company-prefix (car company-candidates))
-                ;; cancel, but last input was actually success
-                (company-cancel company-prefix))
-              (setq company-candidates nil))
-          (backward-delete-char (length new-prefix))
-          (insert company-prefix)
-          (ding)
-          (message "Matching input is required")))
-      company-candidates)))
+    (if (= (- (point) (length new-prefix))
+           (- company-point (length company-prefix)))
+        (unless (or (equal company-prefix new-prefix)
+                    (let ((c (company-calculate-candidates new-prefix)))
+                      ;; t means complete/unique.
+                      (if (eq c t)
+                          (progn (company-cancel new-prefix) t)
+                        (when (consp c)
+                          (setq company-prefix new-prefix)
+                          (company-update-candidates c)
+                          t))))
+          (if (not (and (company-incremental-p company-prefix new-prefix)
+                        (company-require-match-p)))
+              (progn
+                (when (equal company-prefix (car company-candidates))
+                  ;; cancel, but last input was actually success
+                  (company-cancel company-prefix))
+                (setq company-candidates nil))
+            (backward-delete-char (length new-prefix))
+            (insert company-prefix)
+            (ding)
+            (message "Matching input is required")))
+      (when (company-auto-complete-p company-point (point))
+        (save-excursion
+          (goto-char company-point)
+          (company-complete-selection)))
+      (setq company-candidates nil))
+    company-candidates))
 
 (defun company-begin ()
   (when (and (not (and company-candidates (company-continue)))

commit 5ae219807143643f3f6ffd257f901519cd108c39
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 11:08:17 2009 +0200

    Added missing Xcode types.

diff --git a/company-xcode.el b/company-xcode.el
index ac3f4cc..d221d79 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -44,12 +44,13 @@ valid in most contexts."
          (company-xcode-reset))
   :group 'company-xcode
   :type '(set (const "Category") (const "Class") (const "Class Method")
-              (const "Constant") (const "Enum") (const "Field")
-              (const "Instance Method") (const "Instance Variable")
-              (const "Macro") (const "Modeled Class") (const "Modeled Method")
-              (const "Property") (const "Protocol") (const "Structure")
-              (const "Type") (const "Union") (const "Variable")
-              (const "Function")))
+              (const "Class Variable") (const "Constant") (const "Enum")
+              (const "Field") (const "Instance Method")
+              (const "Instance Variable") (const "Macro")
+              (const "Modeled Class") (const "Modeled Method")
+              (const "Modeled Property") (const "Property") (const "Protocol")
+              (const "Structure") (const "Type") (const "Union")
+              (const "Variable") (const "Function")))
 
 (defvar company-xcode-project 'unknown)
 (make-variable-buffer-local 'company-xcode-project)

commit 7f69d3a31c7514ae96a70a98fc83b0a0e564c354
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 17:21:48 2009 +0200

    Cover load errors in auto-loaded back-ends.
    
    Previously, it was enough to ignore errors when requiring.  Since back-ends
    are now interactive and can be auto-loaded, the loading error could occur at
    any time.

diff --git a/company.el b/company.el
index a5eda31..adb0d46 100644
--- a/company.el
+++ b/company.el
@@ -438,7 +438,9 @@ The work-around consists of adding a newline.")
   (when (symbolp backend)
     (unless (fboundp backend)
       (ignore-errors (require backend nil t)))
-    (unless (fboundp backend)
+    (if (and (fboundp backend)
+             (ignore-errors (funcall backend 'init) t))
+        (put backend 'company-init t)
       (message "Company back-end '%s' could not be initialized"
                backend))))
 
@@ -792,7 +794,8 @@ keymap during active completions (`company-active-map'):
                            ;; prefer manual override
                            (list company-backend)
                          company-backends))
-        (when (and (functionp backend)
+        (when (and (get backend 'company-init)
+                   (functionp backend)
                    (setq prefix (funcall backend 'prefix)))
           (when (and (stringp prefix)
                      (>= (length prefix) company-minimum-prefix-length))

commit 5739eb00af23e3a99801a9835d66d448718fae54
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 17:15:46 2009 +0200

    Extracted company-init-backend.

diff --git a/company.el b/company.el
index 16ee7bc..a5eda31 100644
--- a/company.el
+++ b/company.el
@@ -434,6 +434,14 @@ The work-around consists of adding a newline.")
     keymap)
   "Keymap that is enabled during an active completion.")
 
+(defun company-init-backend (backend)
+  (when (symbolp backend)
+    (unless (fboundp backend)
+      (ignore-errors (require backend nil t)))
+    (unless (fboundp backend)
+      (message "Company back-end '%s' could not be initialized"
+               backend))))
+
 ;;;###autoload
 (define-minor-mode company-mode
   "\"complete anything\"; in in-buffer completion framework.
@@ -464,13 +472,7 @@ keymap during active completions (`company-active-map'):
       (progn
         (add-hook 'pre-command-hook 'company-pre-command nil t)
         (add-hook 'post-command-hook 'company-post-command nil t)
-        (dolist (backend company-backends)
-          (when (symbolp backend)
-            (unless (fboundp backend)
-              (ignore-errors (require backend nil t)))
-            (unless (fboundp backend)
-              (message "Company back-end '%s' could not be initialized"
-                       backend)))))
+        (mapc 'company-init-backend company-backends))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
     (company-cancel)

commit 65898da466318e5d43fde742f5e4220eb7f6211a
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 10:57:55 2009 +0200

    Removed unused code.

diff --git a/company.el b/company.el
index 13f6a0b..16ee7bc 100644
--- a/company.el
+++ b/company.el
@@ -294,8 +294,6 @@ does not know about.  It should also be callable 
interactively and use
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
-(defvar start-count 0)
-
 (defcustom company-completion-started-hook nil
   "*Hook run when company starts completing.
 The hook is called with one argument that is non-nil if the completion was

commit 55f2857d75ed3ac504ab56bf63947f55906ec190
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 16:00:22 2009 +0200

    Changed wrong Xcode types.

diff --git a/company-xcode.el b/company-xcode.el
index 463c266..ac3f4cc 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -33,7 +33,7 @@
   (setq company-xcode-tags nil))
 
 (defcustom company-xcode-types
-  '("Class" "Const" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
+  '("Class" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
     "Type" "Union" "Function")
   "*The types of symbols offered by `company-xcode'
 No context-enabled completion is available.  Types like methods will be
@@ -44,8 +44,8 @@ valid in most contexts."
          (company-xcode-reset))
   :group 'company-xcode
   :type '(set (const "Category") (const "Class") (const "Class Method")
-              (const "Const") (const "Constant") (const "Enum") (const "Field")
-              (const "Instance Method") (const "Instance Variables")
+              (const "Constant") (const "Enum") (const "Field")
+              (const "Instance Method") (const "Instance Variable")
               (const "Macro") (const "Modeled Class") (const "Modeled Method")
               (const "Property") (const "Protocol") (const "Structure")
               (const "Type") (const "Union") (const "Variable")

commit f5fa5a28a433f93aaee65293679fc64bddd3618e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 09:49:57 2009 +0200

    Extracted company-call-backend.

diff --git a/company.el b/company.el
index 5d064cb..13f6a0b 100644
--- a/company.el
+++ b/company.el
@@ -549,6 +549,9 @@ keymap during active completions (`company-active-map'):
   (let ((ppss (syntax-ppss)))
     (or (nth 3 ppss) (nth 4 ppss) (nth 7 ppss))))
 
+(defun company-call-backend (&rest args)
+  (apply 'company-backend args))
+
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-backend nil)
@@ -654,7 +657,7 @@ keymap during active completions (`company-active-map'):
   ;; Save in cache:
   (push (cons company-prefix company-candidates) company-candidates-cache)
   ;; Calculate common.
-  (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
+  (let ((completion-ignore-case (company-call-backend 'ignore-case)))
     (setq company-common (try-completion company-prefix company-candidates)))
   (when (eq company-common t)
     (setq company-candidates nil)))
@@ -664,18 +667,18 @@ keymap during active completions (`company-active-map'):
          (or (cdr (assoc prefix company-candidates-cache))
              (when company-candidates-cache
                (let ((len (length prefix))
-                     (completion-ignore-case (funcall company-backend
-                                                      'ignore-case))
+                     (completion-ignore-case (company-call-backend
+                                              'ignore-case))
                      prev)
                  (dotimes (i (1+ len))
                    (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
                                                 company-candidates-cache)))
                      (return (all-completions prefix prev))))))
-             (let ((c (funcall company-backend 'candidates prefix)))
+             (let ((c (company-call-backend 'candidates prefix)))
                (when company-candidates-predicate
                  (setq c (company-apply-predicate
                           c company-candidates-predicate)))
-               (unless (funcall company-backend 'sorted)
+               (unless (company-call-backend 'sorted)
                  (setq c (sort c 'string<)))
                (when (company-call-backend 'duplicates)
                  ;; strip duplicates
@@ -723,7 +726,7 @@ keymap during active completions (`company-active-map'):
        (equal old-prefix (substring new-prefix 0 (length old-prefix)))))
 
 (defun company-require-match-p ()
-  (let ((backend-value (funcall company-backend 'require-match)))
+  (let ((backend-value (company-call-backend 'require-match)))
     (or (eq backend-value t)
         (and (if (functionp company-require-match)
                  (funcall company-require-match)
@@ -748,10 +751,10 @@ keymap during active completions (`company-active-map'):
                          company-auto-complete-chars)))))
 
 (defun company-continue ()
-  (when (funcall company-backend 'no-cache company-prefix)
+  (when (company-call-backend 'no-cache company-prefix)
     ;; Don't complete existing candidates, fetch new ones.
     (setq company-candidates-cache nil))
-  (let ((new-prefix (funcall company-backend 'prefix)))
+  (let ((new-prefix (company-call-backend 'prefix)))
     (unless (and (= (- (point) (length new-prefix))
                     (- company-point (length company-prefix)))
                  (or (equal company-prefix new-prefix)
@@ -1177,7 +1180,7 @@ To show the number next to the candidates in some 
back-ends, enable
   (let ((selected (nth company-selection company-candidates)))
     (unless (equal selected (car company-last-metadata))
       (setq company-last-metadata
-            (cons selected (funcall company-backend 'meta selected))))
+            (cons selected (company-call-backend 'meta selected))))
     (cdr company-last-metadata)))
 
 (defun company-doc-buffer (&optional string)
@@ -1207,7 +1210,7 @@ To show the number next to the candidates in some 
back-ends, enable
   (interactive)
   (company-electric
     (let ((selected (nth company-selection company-candidates)))
-      (display-buffer (or (funcall company-backend 'doc-buffer selected)
+      (display-buffer (or (company-call-backend 'doc-buffer selected)
                           (error "No documentation available")) t))))
 (put 'company-show-doc-buffer 'company-keep t)
 
@@ -1216,7 +1219,7 @@ To show the number next to the candidates in some 
back-ends, enable
   (interactive)
   (company-electric
     (let* ((selected (nth company-selection company-candidates))
-           (location (funcall company-backend 'location selected))
+           (location (company-call-backend 'location selected))
            (pos (or (cdr location) (error "No location available")))
            (buffer (or (and (bufferp (car location)) (car location))
                        (find-file-noselect (car location) t))))

commit 8ae61af3c1e9cdd417858bc8f50c2e70356bbbd5
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 10:27:08 2009 +0200

    Fix incremental cache from empty string.

diff --git a/company.el b/company.el
index 6f8f3f6..5d064cb 100644
--- a/company.el
+++ b/company.el
@@ -667,7 +667,7 @@ keymap during active completions (`company-active-map'):
                      (completion-ignore-case (funcall company-backend
                                                       'ignore-case))
                      prev)
-                 (dotimes (i len)
+                 (dotimes (i (1+ len))
                    (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
                                                 company-candidates-cache)))
                      (return (all-completions prefix prev))))))

commit 9b2fd75a0fa983c4c0accd0eae42bbe8c9bebb6c
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 21:16:17 2009 +0200

    Sped up dabbrev-code by skipping comment chunks.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index f348a18..31ffdd2 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -56,9 +56,10 @@ search other buffers for that many seconds and then return."
           match)
       (while (re-search-forward regexp nil t)
         (setq match (match-string-no-properties 0))
-        (unless (or (eq (match-end 0) pos) ;; ignore match before point
-                    (company-in-string-or-comment))
-          (push match symbols))
+        (if (company-in-string-or-comment)
+            (re-search-forward "\\s>\\|\\s!\\|\\s\"" nil t)
+          (unless (eq (match-end 0) pos) ;; ignore match before point
+            (push match symbols)))
         (and limit
              (eq (incf i) 25)
              (setq i 0)

commit 0be25795c6746f8f2a16e1381f7bfadb688e4b9e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 15:19:42 2009 +0200

    Don't find prefix as abbrev.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index 369cb05..f348a18 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -44,8 +44,8 @@ search other buffers for that many seconds and then return."
                  (const :tag "Same major mode" t)
                  (number :tag "Seconds")))
 
-(defun company-dabbrev-code--buffer-symbols (prefix &optional symbols
-                                            start limit)
+(defun company-dabbrev-code--buffer-symbols (prefix pos &optional symbols
+                                             start limit)
   (save-excursion
     (goto-char (point-min))
     (let ((regexp (concat "\\_<" (if (equal prefix "")
@@ -56,7 +56,8 @@ search other buffers for that many seconds and then return."
           match)
       (while (re-search-forward regexp nil t)
         (setq match (match-string-no-properties 0))
-        (unless (company-in-string-or-comment)
+        (unless (or (eq (match-end 0) pos) ;; ignore match before point
+                    (company-in-string-or-comment))
           (push match symbols))
         (and limit
              (eq (incf i) 25)
@@ -67,13 +68,13 @@ search other buffers for that many seconds and then return."
 
 (defun company-dabbrev-code--symbols (prefix &optional limit)
   (let ((start (current-time))
-        (symbols (company-dabbrev-code--buffer-symbols prefix)))
+        (symbols (company-dabbrev-code--buffer-symbols prefix (point))))
     (dolist (buffer (delq (current-buffer) (buffer-list)))
       (and (eq (buffer-local-value 'major-mode buffer) major-mode)
            (with-current-buffer buffer
              (setq symbols
-                   (company-dabbrev-code--buffer-symbols prefix symbols
-                                                        start limit))))
+                   (company-dabbrev-code--buffer-symbols prefix nil symbols
+                                                         start limit))))
       (and limit
            (> (float-time (time-since start)) limit)
            (return)))
@@ -97,7 +98,7 @@ comments or strings."
                         arg
                         (when (numberp company-dabbrev-code-other-buffers)
                           company-dabbrev-code-other-buffers))
-                     (company-dabbrev-code--buffer-symbols arg))))
+                     (company-dabbrev-code--buffer-symbols arg (point)))))
     ('duplicates t)))
 
 (provide 'company-dabbrev-code)

commit 2aa417878747b9a4488cb912b464a935912d3676
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 21:53:04 2009 +0200

    Let generic code back-end search other buffers.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
index a9d7c28..369cb05 100644
--- a/company-dabbrev-code.el
+++ b/company-dabbrev-code.el
@@ -29,24 +29,56 @@
   "*Modes that use `company-dabbrev-code'.
 In all these modes `company-dabbrev-code' will complete only symbols, not text
 in comments or strings.  In other modes `company-dabbrev-code' will pass 
control
-to other back-ends \(e.g. `company-dabbrev'\)"
+to other back-ends \(e.g. `company-dabbrev'\).
+Value t means complete in all modes."
   :group 'company
-  :type '(repeat (symbol :tag "Major mode")))
+  :type '(choice (repeat (symbol :tag "Major mode"))
+                 (const tag "All modes" t)))
 
-(defun company-dabbrev-code--buffer-symbols (prefix)
+(defcustom company-dabbrev-code-other-buffers .5
+  "*Determines whether `company-dabbrev-code' should search other buffers.
+If t, search all buffers with the same major-mode.  A numeric value means
+search other buffers for that many seconds and then return."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "Same major mode" t)
+                 (number :tag "Seconds")))
+
+(defun company-dabbrev-code--buffer-symbols (prefix &optional symbols
+                                            start limit)
   (save-excursion
     (goto-char (point-min))
     (let ((regexp (concat "\\_<" (if (equal prefix "")
                                      "\\([a-zA-Z]\\|\\s_\\)"
                                    (regexp-quote prefix))
                           "\\(\\sw\\|\\s_\\)*\\_>"))
-           match symbols)
+          (i 0)
+          match)
       (while (re-search-forward regexp nil t)
         (setq match (match-string-no-properties 0))
         (unless (company-in-string-or-comment)
-          (add-to-list 'symbols match)))
+          (push match symbols))
+        (and limit
+             (eq (incf i) 25)
+             (setq i 0)
+             (> (float-time (time-since start)) limit)
+             (return symbols)))
       symbols)))
 
+(defun company-dabbrev-code--symbols (prefix &optional limit)
+  (let ((start (current-time))
+        (symbols (company-dabbrev-code--buffer-symbols prefix)))
+    (dolist (buffer (delq (current-buffer) (buffer-list)))
+      (and (eq (buffer-local-value 'major-mode buffer) major-mode)
+           (with-current-buffer buffer
+             (setq symbols
+                   (company-dabbrev-code--buffer-symbols prefix symbols
+                                                        start limit))))
+      (and limit
+           (> (float-time (time-since start)) limit)
+           (return)))
+    symbols))
+
 ;;;###autoload
 (defun company-dabbrev-code (command &optional arg &rest ignored)
   "A dabbrev-like `company-mode' back-end for code.
@@ -55,11 +87,18 @@ comments or strings."
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-dabbrev-code))
-    ('prefix (and (apply 'derived-mode-p company-dabbrev-code-modes)
+    ('prefix (and (or (eq t company-dabbrev-code-modes)
+                      (apply 'derived-mode-p company-dabbrev-code-modes))
                   (not (company-in-string-or-comment))
                   (or (company-grab-symbol) 'stop)))
     ('candidates (let ((case-fold-search nil))
-                   (company-dabbrev-code--buffer-symbols arg)))))
+                   (if company-dabbrev-code-other-buffers
+                       (company-dabbrev-code--symbols
+                        arg
+                        (when (numberp company-dabbrev-code-other-buffers)
+                          company-dabbrev-code-other-buffers))
+                     (company-dabbrev-code--buffer-symbols arg))))
+    ('duplicates t)))
 
 (provide 'company-dabbrev-code)
 ;;; company-dabbrev-code.el ends here

commit ecc8330075867410def9e95cf6c85408b9d3364a
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 21:21:44 2009 +0200

    Added company-dabbrev-code.

diff --git a/company-dabbrev-code.el b/company-dabbrev-code.el
new file mode 100644
index 0000000..a9d7c28
--- /dev/null
+++ b/company-dabbrev-code.el
@@ -0,0 +1,65 @@
+;;; company-dabbrev-code.el --- a dabbrev-like company-mode back-end for code
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.3.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defcustom company-dabbrev-code-modes
+  '(asm-mode batch-file-mode c++-mode c-mode cperl-mode csharp-mode css-mode
+    emacs-lisp-mode erlang-mode espresso-mode f90-mode fortran-mode
+    haskell-mode java-mode javascript-mode jde-mode js2-mode lisp-mode
+    lua-mode objc-mode perl-mode php-mode python-mode ruby-mode scheme-mode
+    shell-script-mode)
+  "*Modes that use `company-dabbrev-code'.
+In all these modes `company-dabbrev-code' will complete only symbols, not text
+in comments or strings.  In other modes `company-dabbrev-code' will pass 
control
+to other back-ends \(e.g. `company-dabbrev'\)"
+  :group 'company
+  :type '(repeat (symbol :tag "Major mode")))
+
+(defun company-dabbrev-code--buffer-symbols (prefix)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((regexp (concat "\\_<" (if (equal prefix "")
+                                     "\\([a-zA-Z]\\|\\s_\\)"
+                                   (regexp-quote prefix))
+                          "\\(\\sw\\|\\s_\\)*\\_>"))
+           match symbols)
+      (while (re-search-forward regexp nil t)
+        (setq match (match-string-no-properties 0))
+        (unless (company-in-string-or-comment)
+          (add-to-list 'symbols match)))
+      symbols)))
+
+;;;###autoload
+(defun company-dabbrev-code (command &optional arg &rest ignored)
+  "A dabbrev-like `company-mode' back-end for code.
+The back-end looks for all symbols in the current buffer that aren't in
+comments or strings."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-dabbrev-code))
+    ('prefix (and (apply 'derived-mode-p company-dabbrev-code-modes)
+                  (not (company-in-string-or-comment))
+                  (or (company-grab-symbol) 'stop)))
+    ('candidates (let ((case-fold-search nil))
+                   (company-dabbrev-code--buffer-symbols arg)))))
+
+(provide 'company-dabbrev-code)
+;;; company-dabbrev-code.el ends here
diff --git a/company.el b/company.el
index 10f2252..6f8f3f6 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added back-end `company-dabbrev-code' for generic code.
 ;;    Fixed `company-begin-with'.
 ;;
 ;; 2009-04-15 (0.3.1)
@@ -245,7 +246,7 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-xcode company-gtags
                               company-etags company-oddmuse company-files
-                              company-dabbrev)
+                              company-dabbrev-code company-dabbrev)
   "*The list of active back-ends (completion engines).
 Each back-end is a function that takes a variable number of arguments.
 The first argument is the command requested from the back-end.  It is one

commit 455a48ce58ddcc795f8bc6447d6c2b3b2c3edd89
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 19:18:35 2009 +0200

    Added option to remove duplicates among candidates.

diff --git a/company.el b/company.el
index ca0f801..10f2252 100644
--- a/company.el
+++ b/company.el
@@ -264,6 +264,9 @@ Optional commands:
 'sorted: The back-end may return t here to indicate that the candidates
 are sorted and will not need to be sorted again.
 
+'duplicates: If non-nil, company will take care of removing duplicates
+from the list.
+
 'no-cache: Usually company doesn't ask for candidates again as completion
 progresses, unless the back-end returns t for this command.  The second
 argument is the latest prefix.
@@ -673,6 +676,12 @@ keymap during active completions (`company-active-map'):
                           c company-candidates-predicate)))
                (unless (funcall company-backend 'sorted)
                  (setq c (sort c 'string<)))
+               (when (company-call-backend 'duplicates)
+                 ;; strip duplicates
+                 (let ((c2 c))
+                   (while c2
+                     (setcdr c2 (progn (while (equal (pop c2) (car c2)))
+                                       c2)))))
                c))))
     (if (or (cdr candidates)
             (not (equal (car candidates) prefix)))

commit f8c6044b768393b0c23bacc05c169c0dac3422ed
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 16 09:25:32 2009 +0200

    Fixed docstring that confused syntax highlighting.

diff --git a/company.el b/company.el
index 9660b86..ca0f801 100644
--- a/company.el
+++ b/company.el
@@ -254,7 +254,7 @@ of the following:
 'prefix: The back-end should return the text to be completed.  It must be
 text immediately before `point'.  Returning nil passes control to the next
 back-end.  The function should return 'stop if it should complete but cannot
-(e.g. if it is in the middle of a string).
+\(e.g. if it is in the middle of a string\).
 
 'candidates: The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.

commit 7c54c736a42fe7b7989f68f6ce6947155ddeab2d
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 22:38:32 2009 +0200

    Prevent accidental continue when moving point.

diff --git a/company.el b/company.el
index 1c6af8b..9660b86 100644
--- a/company.el
+++ b/company.el
@@ -772,9 +772,8 @@ keymap during active completions (`company-active-map'):
       company-candidates)))
 
 (defun company-begin ()
-  (when (if company-candidates
-            (not (company-continue))
-          (company--should-complete))
+  (when (and (not (and company-candidates (company-continue)))
+             (company--should-complete))
     (let (prefix)
       (dolist (backend (if company-backend
                            ;; prefer manual override

commit aaa0bded726c6e1f6ed13884bdc84154af083fe4
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 20:22:50 2009 +0200

    Fixed company-begin-with.

diff --git a/company.el b/company.el
index 3be107e..1c6af8b 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Fixed `company-begin-with'.
+;;
 ;; 2009-04-15 (0.3.1)
 ;;    Added 'stop prefix to prevent dabbrev from completing inside of symbols.
 ;;    Fixed issues with tabbar-mode and line-spacing.
@@ -1221,9 +1223,14 @@ To show the number next to the candidates in some 
back-ends, enable
 (defvar company-callback nil)
 (make-variable-buffer-local 'company-callback)
 
+(defvar company-begin-with-marker nil)
+(make-variable-buffer-local 'company-begin-with-marker)
+
 (defun company-remove-callback (&optional ignored)
   (remove-hook 'company-completion-finished-hook company-callback t)
-  (remove-hook 'company-completion-cancelled-hook 'company-remove-callback t))
+  (remove-hook 'company-completion-cancelled-hook 'company-remove-callback t)
+  (remove-hook 'company-completion-finished-hook 'company-remove-callback t)
+  (set-marker company-begin-with-marker nil))
 
 (defun company-begin-backend (backend &optional callback)
   "Start a completion at point using BACKEND."
@@ -1232,13 +1239,10 @@ To show the number next to the candidates in some 
back-ends, enable
                                            'functionp nil "company-")))
                  (when val
                    (list (intern val)))))
-  (when callback
-    (setq company-callback
-          `(lambda (completion)
-             (funcall ',callback completion)
-             (company-remove-callback)))
-    (add-hook 'company-completion-cancelled-hook 'company-remove-callback nil 
t)
+  (when (setq company-callback callback)
     (add-hook 'company-completion-finished-hook company-callback nil t))
+  (add-hook 'company-completion-cancelled-hook 'company-remove-callback nil t)
+  (add-hook 'company-completion-finished-hook 'company-remove-callback nil t)
   (setq company-backend backend)
   ;; Return non-nil if active.
   (or (company-manual-begin)
@@ -1257,10 +1261,11 @@ Example:
 \(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
   (company-begin-backend
    (let ((start (- (point) (or prefix-length 0))))
+     (setq company-begin-with-marker (copy-marker (point) t))
      `(lambda (command &optional arg &rest ignored)
-        (case command-history
-          ('prefix (message "prefix %s" (buffer-substring ,start (point)))
-                   (when (>= (point) ,start)
+        (case command
+          ('prefix (when (equal (point)
+                                (marker-position company-begin-with-marker))
                      (buffer-substring ,start (point))))
           ('candidates (all-completions arg ',candidates))
           ('require-match ,require-match))))

commit e67e41c485387f693e3c2ebfb07cf86fe40df804
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 10:22:37 2009 +0200

    Bumped version to 0.3.1.

diff --git a/company-abbrev.el b/company-abbrev.el
index ab017aa..7a6d6ec 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index af6608c..2e972a6 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index e0a4a90..c0379ff 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index a501efe..bb08355 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index fcf7856..db6a1aa 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index c081558..2d60cee 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 083bc77..146cb12 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index b32a332..8602745 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index aad2fc2..06ad0bc 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index c649c3c..19ba24b 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index 90d3d3f..29ba893 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index 27c05ad..483db6a 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 56c6898..463c266 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.3.
+;; This file is part of company 0.3.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index c4bd200..3be107e 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.3
+;; Version: 0.3.1
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-15 (0.3.1)
 ;;    Added 'stop prefix to prevent dabbrev from completing inside of symbols.
 ;;    Fixed issues with tabbar-mode and line-spacing.
 ;;    Performance enhancements.

commit 02a133d472a0a3cecf208f658141591ea83ebe35
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 10:20:03 2009 +0200

    Fetch Xcode tags later.

diff --git a/company-xcode.el b/company-xcode.el
index 725f3f8..56c6898 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -100,9 +100,9 @@ valid in most contexts."
     ('interactive (company-begin-backend 'company-xcode))
     ('prefix (and company-xcode-xcodeindex-executable
                   (not (company-in-string-or-comment))
-                  (company-xcode-tags)
                   (or (company-grab-symbol) 'stop)))
     ('candidates (let ((completion-ignore-case nil))
+                   (company-xcode-tags)
                    (all-completions arg (company-xcode-tags))))))
 
 

commit 3300b2d2b1a199d666bf261a1882aaaaa0d5af5b
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 09:59:51 2009 +0200

    Support 'stop return value for 'prefix command.

diff --git a/company-elisp.el b/company-elisp.el
index 5c7a11e..a501efe 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -109,7 +109,7 @@ Functions are offered for completion only after ' and \(."
   (case command
     ('interactive (company-begin-backend 'company-elisp))
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
-                  (company-grab-lisp-symbol)))
+                  (or (company-grab-lisp-symbol) 'stop)))
     ('candidates (company-elisp-candidates arg))
     ('meta (company-elisp-doc arg))
     ('doc-buffer (let ((symbol (intern arg)))
diff --git a/company-etags.el b/company-etags.el
index a2fa131..fcf7856 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -63,7 +63,7 @@ buffer automatically."
                   (not (company-in-string-or-comment))
                   (require 'etags nil t)
                   (company-etags-buffer-table)
-                  (company-grab-symbol)))
+                  (or (company-grab-symbol) 'stop)))
     ('candidates (let ((tags-table-list (company-etags-buffer-table))
                        (completion-ignore-case nil))
                    (and (fboundp 'tags-completion-table)
diff --git a/company-gtags.el b/company-gtags.el
index b4dedeb..083bc77 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -60,7 +60,7 @@
     ('prefix (and company-gtags-executable
                   (memq major-mode company-gtags-modes)
                   (not (company-in-string-or-comment))
-                  (company-grab-symbol)))
+                  (or (company-grab-symbol) 'stop)))
     ('candidates (company-gtags-fetch-tags arg))
     ('sorted t)
     ('location (company-gtags-location arg))))
diff --git a/company-semantic.el b/company-semantic.el
index 93b5441..90d3d3f 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -74,7 +74,7 @@
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
                   (semantic-active-p)
                   (not (company-in-string-or-comment))
-                  (company-grab-symbol)))
+                  (or (company-grab-symbol) 'stop)))
     ('candidates (or (company-semantic-completions arg)
                      (company-semantic-completions-raw arg)))
     ('meta (funcall company-semantic-metadata-function
diff --git a/company-xcode.el b/company-xcode.el
index 8e068ad..725f3f8 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -101,7 +101,7 @@ valid in most contexts."
     ('prefix (and company-xcode-xcodeindex-executable
                   (not (company-in-string-or-comment))
                   (company-xcode-tags)
-                  (company-grab-symbol)))
+                  (or (company-grab-symbol) 'stop)))
     ('candidates (let ((completion-ignore-case nil))
                    (all-completions arg (company-xcode-tags))))))
 
diff --git a/company.el b/company.el
index 598bf56..c4bd200 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added 'stop prefix to prevent dabbrev from completing inside of symbols.
 ;;    Fixed issues with tabbar-mode and line-spacing.
 ;;    Performance enhancements.
 ;;
@@ -249,7 +250,8 @@ of the following:
 
 'prefix: The back-end should return the text to be completed.  It must be
 text immediately before `point'.  Returning nil passes control to the next
-back-end.
+back-end.  The function should return 'stop if it should complete but cannot
+(e.g. if it is in the middle of a string).
 
 'candidates: The second argument is the prefix to be completed.  The
 return value should be a list of candidates that start with the prefix.
@@ -526,13 +528,15 @@ keymap during active completions (`company-active-map'):
   (if (looking-at "\\_>")
       (buffer-substring (point) (save-excursion (skip-syntax-backward "w_")
                                                 (point)))
-    ""))
+    (unless (and (char-after) (memq (char-syntax (char-after)) '(?w ?_)))
+      "")))
 
 (defun company-grab-word ()
   (if (looking-at "\\>")
       (buffer-substring (point) (save-excursion (skip-syntax-backward "w")
                                                 (point)))
-    ""))
+    (unless (and (char-after) (eq (char-syntax (char-after)) ?w))
+      "")))
 
 (defun company-in-string-or-comment ()
   (let ((ppss (syntax-ppss)))
@@ -775,12 +779,13 @@ keymap during active completions (`company-active-map'):
                          company-backends))
         (when (and (functionp backend)
                    (setq prefix (funcall backend 'prefix)))
-          (setq company-backend backend)
-          (when (>= (length prefix) company-minimum-prefix-length)
+          (when (and (stringp prefix)
+                     (>= (length prefix) company-minimum-prefix-length))
+            (setq company-backend backend
+                  company-prefix prefix)
             (let ((c (company-calculate-candidates prefix)))
               ;; t means complete/unique.  We don't start, so no hooks.
               (when (consp c)
-                (setq company-prefix prefix)
                 (company-update-candidates c)
                 (run-hook-with-args 'company-completion-started-hook
                                     (company-explicit-action-p))

commit f61379ef40c892685eccf1d34513d6a91df01898
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 09:41:59 2009 +0200

    Make sure tooltip numbers are cropped correctly at the window edge.

diff --git a/company.el b/company.el
index 5a09eb8..598bf56 100644
--- a/company.el
+++ b/company.el
@@ -1398,9 +1398,8 @@ Example:
     (setq lines-copy lines)
 
     ;; number can make tooltip too long
-    (and company-show-numbers
-         (< (setq numbered company-tooltip-offset) 10)
-         (incf width 2))
+    (when company-show-numbers
+      (setq numbered company-tooltip-offset))
 
     (when previous
       (push (propertize (company-safe-substring previous 0 width)

commit 3b7222b35e4ec15902804b9b1741b9e0f2d45646
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 15 09:13:54 2009 +0200

    Added Makefile with packaging commands.

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d49adf3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+package: *.el
+       @ver=`grep -o "Version: .*" company.el | cut -c 10-`; \
+       tar cjvf company-$$ver.tar.bz2 --mode 644 `git ls-files '*.el' | xargs`
+
+elpa: *.el
+       @version=`grep -o "Version: .*" company.el | cut -c 10-`; \
+       dir=company-$$version; \
+       mkdir -p "$$dir"; \
+       cp `git ls-files '*.el' | xargs` company-$$version; \
+       echo "(define-package \"company\" \"$$version\" \
+       \"extensible inline text completion mechanism\")" \
+       > "$$dir"/company-pkg.el; \
+       tar cvf company-$$version.tar --mode 644 "$$dir"
+
+clean:
+       @rm -rf company-*/ company-*.tar company-*.tar.bz2

commit a19829a213fe39f3705dcdd7c76a6d025a4d3a75
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 22:55:28 2009 +0200

    Work around mysterious pseudo-tooltip error.

diff --git a/company.el b/company.el
index 6b0b7bd..5a09eb8 100644
--- a/company.el
+++ b/company.el
@@ -1464,8 +1464,9 @@ Example:
 
 (defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (posn-actual-col-row (posn-at-point pos))))
-    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
-                                 company-selection)))
+    (when col-row
+      (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
+                                   company-selection))))
 
 (defun company-pseudo-tooltip-edit (lines selection)
   (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))

commit 44f9398832b365b5323a03c2948b5752217b07a2
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 22:23:35 2009 +0200

    Remove includes and empty candidates in semantic.

diff --git a/company-semantic.el b/company-semantic.el
index 6f10af8..93b5441 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -58,6 +58,13 @@
           (context (semantic-analyze-current-context)))
       (all-completions prefix (semantic-ia-get-completions context (point))))))
 
+(defun company-semantic-completions-raw (prefix)
+  (let (candidates)
+    (dolist (tag (semantic-analyze-find-tags-by-prefix prefix))
+      (unless (eq (semantic-tag-class tag) 'include)
+        (push (semantic-tag-name tag) candidates)))
+    (delete "" candidates)))
+
 ;;;###autoload
 (defun company-semantic (command &optional arg &rest ignored)
   "A `company-mode' completion back-end using CEDET Semantic."
@@ -69,8 +76,7 @@
                   (not (company-in-string-or-comment))
                   (company-grab-symbol)))
     ('candidates (or (company-semantic-completions arg)
-                     (mapcar 'semantic-tag-name
-                             (semantic-analyze-find-tags-by-prefix arg))))
+                     (company-semantic-completions-raw arg)))
     ('meta (funcall company-semantic-metadata-function
                     (semantic-analyze-find-tag arg)))
     ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))

commit 38b6002b3638d173be6b43153f8b3471a702e21f
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 21:54:30 2009 +0200

    Made gtags behave like xcode back-end.

diff --git a/company-gtags.el b/company-gtags.el
index a5e97e4..b4dedeb 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -20,40 +20,29 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
-(defcustom company-gtags-gnu-global-program-name
-  (or (locate-file "global" exec-path exec-suffixes 'file-executable-p)
-      "global")
+(defcustom company-gtags-executable
+  (executable-find "global")
   "*Location of GNU global executable"
   :type 'string
   :group 'company)
 
-(defvar company-gtags-modes '(c-mode c++-mode jde-mode java-mode php-mode))
-
-(defvar company-gtags-available 'unknown)
-(make-variable-buffer-local 'company-gtags-available)
+(define-obsolete-variable-alias
+  'company-gtags-gnu-global-program-name
+  'company-gtags-executable)
 
-(defun company-gtags-available ()
-  (when (eq company-gtags-available 'unknown)
-    (condition-case err
-        (setq company-gtags-available
-              (= 0 (call-process company-gtags-gnu-global-program-name
-                                 nil nil nil "-c" "WHATEVER")))
-      (error
-       (message "Company: GNU Global not found")
-       (setq-default company-gtags-available nil))))
-  company-gtags-available)
+(defvar company-gtags-modes '(c-mode c++-mode jde-mode java-mode php-mode))
 
 (defun company-gtags-fetch-tags (prefix)
   (with-temp-buffer
     (let (tags)
-      (when (= 0 (call-process company-gtags-gnu-global-program-name nil
+      (when (= 0 (call-process company-gtags-executable nil
                                (list (current-buffer) nil) nil "-c" prefix))
         (goto-char (point-min))
         (split-string (buffer-string) "\n" t)))))
 
 (defun company-gtags-location (tag)
   (with-temp-buffer
-    (when (= 0 (call-process company-gtags-gnu-global-program-name nil
+    (when (= 0 (call-process company-gtags-executable nil
                              (list (current-buffer) nil) nil "-x" tag))
         (goto-char (point-min))
         (when (looking-at (concat (regexp-quote tag)
@@ -68,10 +57,10 @@
   (interactive (list 'interactive))
   (case command
     ('interactive (company-begin-backend 'company-gtags))
-    ('prefix (and (memq major-mode company-gtags-modes)
+    ('prefix (and company-gtags-executable
+                  (memq major-mode company-gtags-modes)
                   (not (company-in-string-or-comment))
-                  (company-gtags-available)
-               (company-grab-symbol)))
+                  (company-grab-symbol)))
     ('candidates (company-gtags-fetch-tags arg))
     ('sorted t)
     ('location (company-gtags-location arg))))

commit 06ee5810059d3fdab1851e1fce9fa955750e69b7
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 21:40:59 2009 +0200

    Actually use company-gtags-gnu-global-program-name.

diff --git a/company-gtags.el b/company-gtags.el
index c8b32b1..a5e97e4 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -23,7 +23,7 @@
 (defcustom company-gtags-gnu-global-program-name
   (or (locate-file "global" exec-path exec-suffixes 'file-executable-p)
       "global")
-  "*"
+  "*Location of GNU global executable"
   :type 'string
   :group 'company)
 
@@ -46,15 +46,15 @@
 (defun company-gtags-fetch-tags (prefix)
   (with-temp-buffer
     (let (tags)
-      (when (= 0 (call-process "global" nil (list (current-buffer) nil)
-                               nil "-c" prefix))
+      (when (= 0 (call-process company-gtags-gnu-global-program-name nil
+                               (list (current-buffer) nil) nil "-c" prefix))
         (goto-char (point-min))
         (split-string (buffer-string) "\n" t)))))
 
 (defun company-gtags-location (tag)
   (with-temp-buffer
-    (when (= 0 (call-process "global" nil (list (current-buffer) nil)
-                               nil "-x" tag))
+    (when (= 0 (call-process company-gtags-gnu-global-program-name nil
+                             (list (current-buffer) nil) nil "-x" tag))
         (goto-char (point-min))
         (when (looking-at (concat (regexp-quote tag)
                                   "[ \t]+\\([[:digit:]]+\\)"

commit f79c4c78c48a46bbc8dffdbf3034a2d42abc85c6
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 21:28:56 2009 +0200

    Removed unused code.

diff --git a/company.el b/company.el
index 05a7d04..6b0b7bd 100644
--- a/company.el
+++ b/company.el
@@ -772,7 +772,7 @@ keymap during active completions (`company-active-map'):
       (dolist (backend (if company-backend
                            ;; prefer manual override
                            (list company-backend)
-                         (cons company-backend company-backends)))
+                         company-backends))
         (when (and (functionp backend)
                    (setq prefix (funcall backend 'prefix)))
           (setq company-backend backend)

commit ec387be2cb89096fac6c690a1cf9427850bed5a7
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 20:43:50 2009 +0200

    Added reference to company-show-numbers in company-complete-number.

diff --git a/company.el b/company.el
index 8bff9de..05a7d04 100644
--- a/company.el
+++ b/company.el
@@ -1118,7 +1118,9 @@ when the selection has been changed, the selected 
candidate is completed."
       (setq this-command 'company-complete-common))))
 
 (defun company-complete-number (n)
-  "Complete the Nth candidate."
+  "Complete the Nth candidate.
+To show the number next to the candidates in some back-ends, enable
+`company-show-numbers'."
   (when (company-manual-begin)
     (and (< n 1) (> n company-candidates-length)
          (error "No candidate number %d" n))

commit ddf7cb15af1271dd83d65bc79c0c318cd0bd44eb
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 20:11:48 2009 +0200

    Retrieve prefix less frequently.

diff --git a/company.el b/company.el
index 48f4919..8bff9de 100644
--- a/company.el
+++ b/company.el
@@ -594,13 +594,14 @@ keymap during active completions (`company-active-map'):
   ;; It's mory efficient to fix it only when they are displayed.
   (concat company-prefix (substring candidate (length company-prefix))))
 
-(defsubst company-should-complete (prefix)
-  (and (eq company-idle-delay t)
+(defun company--should-complete ()
+  (and (not (or buffer-read-only overriding-terminal-local-map
+                overriding-local-map))
+       (eq company-idle-delay t)
        (or (eq t company-begin-commands)
            (memq company--this-command company-begin-commands)
            (and (symbolp this-command) (get this-command 'company-begin)))
-       (not (and transient-mark-mode mark-active))
-       (>= (length prefix) company-minimum-prefix-length)))
+       (not (and transient-mark-mode mark-active))))
 
 (defsubst company-call-frontends (command)
   (dolist (frontend company-frontends)
@@ -730,64 +731,61 @@ keymap during active completions (`company-active-map'):
                          company-auto-complete-chars)))))
 
 (defun company-continue ()
-  (when company-candidates
-    (when (funcall company-backend 'no-cache company-prefix)
-      ;; Don't complete existing candidates, fetch new ones.
-      (setq company-candidates-cache nil))
-    (let ((new-prefix (funcall company-backend 'prefix)))
-      (unless (and (= (- (point) (length new-prefix))
-                      (- company-point (length company-prefix)))
-                   (or (equal company-prefix new-prefix)
-                       (let ((c (company-calculate-candidates new-prefix)))
-                         ;; t means complete/unique.
-                         (if (eq c t)
-                             (progn (company-cancel new-prefix) t)
-                           (when (consp c)
-                             (setq company-prefix new-prefix)
-                             (company-update-candidates c)
-                             t)))))
-        (if (company-auto-complete-p company-point (point))
-            (save-excursion
-              (goto-char company-point)
-              (company-complete-selection)
+  (when (funcall company-backend 'no-cache company-prefix)
+    ;; Don't complete existing candidates, fetch new ones.
+    (setq company-candidates-cache nil))
+  (let ((new-prefix (funcall company-backend 'prefix)))
+    (unless (and (= (- (point) (length new-prefix))
+                    (- company-point (length company-prefix)))
+                 (or (equal company-prefix new-prefix)
+                     (let ((c (company-calculate-candidates new-prefix)))
+                       ;; t means complete/unique.
+                       (if (eq c t)
+                           (progn (company-cancel new-prefix) t)
+                         (when (consp c)
+                           (setq company-prefix new-prefix)
+                           (company-update-candidates c)
+                           t)))))
+      (if (company-auto-complete-p company-point (point))
+          (save-excursion
+            (goto-char company-point)
+            (company-complete-selection)
+            (setq company-candidates nil))
+        (if (not (and (company-incremental-p company-prefix new-prefix)
+                      (company-require-match-p)))
+            (progn
+              (when (equal company-prefix (car company-candidates))
+                ;; cancel, but last input was actually success
+                (company-cancel company-prefix))
               (setq company-candidates nil))
-          (if (not (and (company-incremental-p company-prefix new-prefix)
-                        (company-require-match-p)))
-              (progn
-                (when (equal company-prefix (car company-candidates))
-                  ;; cancel, but last input was actually success
-                  (company-cancel company-prefix))
-                (setq company-candidates nil))
-            (backward-delete-char (length new-prefix))
-            (insert company-prefix)
-            (ding)
-            (message "Matching input is required")))
-        company-candidates))))
+          (backward-delete-char (length new-prefix))
+          (insert company-prefix)
+          (ding)
+          (message "Matching input is required")))
+      company-candidates)))
 
 (defun company-begin ()
-  (if (or buffer-read-only overriding-terminal-local-map overriding-local-map)
-      ;; Don't complete in these cases.
-      (setq company-candidates nil)
-    (company-continue)
-    (unless company-candidates
-      (let (prefix)
-        (dolist (backend (if company-backend
-                             ;; prefer manual override
-                             (list company-backend)
-                           (cons company-backend company-backends)))
-          (when (and (functionp backend)
-                     (setq prefix (funcall backend 'prefix)))
-            (setq company-backend backend)
-            (when (company-should-complete prefix)
-              (let ((c (company-calculate-candidates prefix)))
-                ;; t means complete/unique.  We don't start, so no hooks.
-                (when (consp c)
-                  (setq company-prefix prefix)
-                  (company-update-candidates c)
-                  (run-hook-with-args 'company-completion-started-hook
-                                      (company-explicit-action-p))
-                  (company-call-frontends 'show))))
-            (return prefix))))))
+  (when (if company-candidates
+            (not (company-continue))
+          (company--should-complete))
+    (let (prefix)
+      (dolist (backend (if company-backend
+                           ;; prefer manual override
+                           (list company-backend)
+                         (cons company-backend company-backends)))
+        (when (and (functionp backend)
+                   (setq prefix (funcall backend 'prefix)))
+          (setq company-backend backend)
+          (when (>= (length prefix) company-minimum-prefix-length)
+            (let ((c (company-calculate-candidates prefix)))
+              ;; t means complete/unique.  We don't start, so no hooks.
+              (when (consp c)
+                (setq company-prefix prefix)
+                (company-update-candidates c)
+                (run-hook-with-args 'company-completion-started-hook
+                                    (company-explicit-action-p))
+                (company-call-frontends 'show))))
+          (return prefix)))))
   (if company-candidates
       (progn
         (when (and company-end-of-buffer-workaround (eobp))

commit 1b7b06fdfffbcb8da77b870c9a7dfa4857bbc163
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 18:35:31 2009 +0200

    Removed unused arg to company-in-string-or-comment.

diff --git a/company-elisp.el b/company-elisp.el
index 74f8897..5c7a11e 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -30,7 +30,7 @@ Functions are offered for completion only after ' and \(."
 
 (defun company-grab-lisp-symbol ()
   (let ((prefix (company-grab-symbol)))
-    (unless (and (company-in-string-or-comment (- (point) (length prefix)))
+    (unless (and (company-in-string-or-comment)
                  (/= (char-before (- (point) (length prefix))) ?`))
       prefix)))
 
diff --git a/company.el b/company.el
index 27c95fb..48f4919 100644
--- a/company.el
+++ b/company.el
@@ -534,9 +534,9 @@ keymap during active completions (`company-active-map'):
                                                 (point)))
     ""))
 
-(defun company-in-string-or-comment (&optional point)
-  (let ((pos (syntax-ppss)))
-    (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
+(defun company-in-string-or-comment ()
+  (let ((ppss (syntax-ppss)))
+    (or (nth 3 ppss) (nth 4 ppss) (nth 7 ppss))))
 
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 3fd5fd38dfdf85074d96f13d9893cfb479ff0681
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 12:02:17 2009 +0200

    Fixed issues with tabbar-mode and line-spacing.
    
    See also Emacs bug #2993.

diff --git a/company.el b/company.el
index 8aad116..27c95fb 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Fixed issues with tabbar-mode and line-spacing.
 ;;    Performance enhancements.
 ;;
 ;; 2009-04-12 (0.3)
@@ -1080,8 +1081,8 @@ followed by `company-search-kill-others' after each 
input."
   "Select the candidate picked by the mouse."
   (interactive "e")
   (when (nth 4 (event-start event))
-    (company-set-selection (- (cdr (posn-col-row (event-start event)))
-                              (cdr (posn-col-row (posn-at-point)))
+    (company-set-selection (- (cdr (posn-actual-col-row (event-start event)))
+                              (cdr (posn-actual-col-row (posn-at-point)))
                               1))
     t))
 
@@ -1172,7 +1173,7 @@ when the selection has been changed, the selected 
candidate is completed."
   `(when (company-manual-begin)
      (save-window-excursion
        (let ((height (window-height))
-             (row (cdr (posn-col-row (posn-at-point)))))
+             (row (cdr (posn-actual-col-row (posn-at-point)))))
          ,@body
          (and (< (window-height) height)
               (< (- (window-height) row 2) company-tooltip-limit)
@@ -1336,7 +1337,7 @@ Example:
 
 (defun company-buffer-lines (beg end)
   (goto-char beg)
-  (let ((row (cdr (posn-col-row (posn-at-point))))
+  (let ((row (cdr (posn-actual-col-row (posn-at-point))))
         lines)
     (while (and (equal (move-to-window-line (incf row)) row)
                 (<= (point) end))
@@ -1462,8 +1463,9 @@ Example:
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
-  (let ((col-row (posn-col-row (posn-at-point pos))))
-    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row) 
company-selection)))
+  (let ((col-row (posn-actual-col-row (posn-at-point pos))))
+    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
+                                 company-selection)))
 
 (defun company-pseudo-tooltip-edit (lines selection)
   (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))

commit 9931669f97289c194a68995652042df36719cd5c
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 18:03:34 2009 +0200

    Made company-begin-commands handling more robust.

diff --git a/company.el b/company.el
index 288a486..8aad116 100644
--- a/company.el
+++ b/company.el
@@ -570,6 +570,8 @@ keymap during active completions (`company-active-map'):
   "Non-nil, if explicit completion took place.")
 (make-variable-buffer-local 'company--explicit-action)
 
+(defvar company--this-command nil)
+
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
@@ -594,7 +596,7 @@ keymap during active completions (`company-active-map'):
 (defsubst company-should-complete (prefix)
   (and (eq company-idle-delay t)
        (or (eq t company-begin-commands)
-           (memq this-command company-begin-commands)
+           (memq company--this-command company-begin-commands)
            (and (symbolp this-command) (get this-command 'company-begin)))
        (not (and transient-mark-mode mark-active))
        (>= (length prefix) company-minimum-prefix-length)))
@@ -856,6 +858,7 @@ keymap during active completions (`company-active-map'):
   (unless (company-keep this-command)
     (condition-case err
         (progn
+          (setq company--this-command this-command)
           (unless (equal (point) company-point)
             (company-begin))
           (when company-candidates

commit f52dcb091e2cfb821ef96c21679a1449d45d4780
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 11:14:00 2009 +0200

    Fixed typo.

diff --git a/company.el b/company.el
index ad86054..288a486 100644
--- a/company.el
+++ b/company.el
@@ -339,7 +339,7 @@ the selected completion.  This can also be a function."
   "Determines which characters trigger an automatic completion.
 See `company-auto-complete'.  If this is a string, each string character causes
 completion.  If it is a list of syntax description characters (see
-`modify-char-syntax'), all characters with that syntax auto-complete.
+`modify-syntax-entry'), all characters with that syntax auto-complete.
 
 This can also be a function, which is called with the new input and should
 return non-nil if company should auto-complete.

commit cf1c75514a0c54c3d777f10b1785164dca9c8729
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 14 10:14:48 2009 +0200

    Added faster and more convenient grab functions.

diff --git a/company-abbrev.el b/company-abbrev.el
index 5925977..ab017aa 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -32,7 +32,7 @@
   (case command
         ('interactive (company-begin-backend 'company-abbrev
                                              'company-abbrev-insert))
-        ('prefix (or (company-grab "\\_<\\(\\sw\\|\\s_\\)+\\_>") ""))
+        ('prefix (company-grab-symbol))
         ('candidates (nconc
                       (delete "" (all-completions arg global-abbrev-table))
                       (delete "" (all-completions arg local-abbrev-table))))
diff --git a/company-css.el b/company-css.el
index dcb58a1..af6608c 100644
--- a/company-css.el
+++ b/company-css.el
@@ -263,8 +263,7 @@
   "Return the CSS property before point, if any.
 Returns \"\" if no property found, but feasible at this position."
   (when (company-css-inside-braces-p)
-    (or (company-grab "\\_<[[:alpha:]-]+\\_>\\=")
-        (company-grab "{\\|[[:space:]]" 1))))
+    (company-grab-symbol)))
 
 ;;; values
 (defconst company-css-property-value-regexp
diff --git a/company-elisp.el b/company-elisp.el
index d902c4d..74f8897 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -28,11 +28,8 @@ Functions are offered for completion only after ' and \(."
   :type '(choice (const :tag "Off" nil)
                  (const :tag "On" t)))
 
-(defvar company-lisp-symbol-regexp
-  "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
-
 (defun company-grab-lisp-symbol ()
-  (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
+  (let ((prefix (company-grab-symbol)))
     (unless (and (company-in-string-or-comment (- (point) (length prefix)))
                  (/= (char-before (- (point) (length prefix))) ?`))
       prefix)))
diff --git a/company-etags.el b/company-etags.el
index 820ffee..a2fa131 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -29,9 +29,6 @@ buffer automatically."
   :type '(choice (const :tag "off" nil)
                  (const :tag "on" t)))
 
-(defvar company-etags-symbol-regexp
-  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
-
 (defvar company-etags-modes '(c-mode objc-mode c++-mode java-mode jde-mode
                               pascal-mode perl-mode python-mode))
 
@@ -66,7 +63,7 @@ buffer automatically."
                   (not (company-in-string-or-comment))
                   (require 'etags nil t)
                   (company-etags-buffer-table)
-                  (or (company-grab company-etags-symbol-regexp) "")))
+                  (company-grab-symbol)))
     ('candidates (let ((tags-table-list (company-etags-buffer-table))
                        (completion-ignore-case nil))
                    (and (fboundp 'tags-completion-table)
diff --git a/company-files.el b/company-files.el
index cdb8bf1..c081558 100644
--- a/company-files.el
+++ b/company-files.el
@@ -28,9 +28,9 @@
 
 (defun company-files-grab-existing-name ()
   ;; Grab file names with spaces, only when they include quotes.
-  (let ((file (or (company-grab "\"\\(~?/[^\"\n]*\\)" 1)
-                  (company-grab "\'\\(~?/[^\'\n]*\\)" 1)
-                  (company-grab "[ \t\n]\\(~?/[^ \t\n]*\\)" 1)))
+  (let ((file (or (company-grab-line "\"\\(~?/[^\"\n]*\\)" 1)
+                  (company-grab-line "\'\\(~?/[^\'\n]*\\)" 1)
+                  (company-grab-line "[ \t\n]\\(~?/[^ \t\n]*\\)" 1)))
         dir)
     (and file
          (setq dir (file-name-directory file))
diff --git a/company-gtags.el b/company-gtags.el
index e9aca67..c8b32b1 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -27,9 +27,6 @@
   :type 'string
   :group 'company)
 
-(defvar company-gtags-symbol-regexp
-  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
-
 (defvar company-gtags-modes '(c-mode c++-mode jde-mode java-mode php-mode))
 
 (defvar company-gtags-available 'unknown)
@@ -52,10 +49,7 @@
       (when (= 0 (call-process "global" nil (list (current-buffer) nil)
                                nil "-c" prefix))
         (goto-char (point-min))
-        (while (looking-at company-gtags-symbol-regexp)
-          (push (match-string-no-properties 0) tags)
-          (forward-line)))
-      (nreverse tags))))
+        (split-string (buffer-string) "\n" t)))))
 
 (defun company-gtags-location (tag)
   (with-temp-buffer
@@ -77,7 +71,7 @@
     ('prefix (and (memq major-mode company-gtags-modes)
                   (not (company-in-string-or-comment))
                   (company-gtags-available)
-               (or (company-grab company-gtags-symbol-regexp) "")))
+               (company-grab-symbol)))
     ('candidates (company-gtags-fetch-tags arg))
     ('sorted t)
     ('location (company-gtags-location arg))))
diff --git a/company-ispell.el b/company-ispell.el
index fbbeda3..b32a332 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -48,7 +48,7 @@ If nil, use `ispell-complete-word-dict'."
   (case command
     ('interactive (company-begin-backend 'company-ispell))
     ('prefix (when (company-ispell-available)
-               (company-grab "\\<\\w+\\>")))
+               (company-grab-word)))
     ('candidates (lookup-words arg (or company-ispell-dictionary
                                        ispell-complete-word-dict)))
     ('sorted t)
diff --git a/company-semantic.el b/company-semantic.el
index e1cfbda..6f10af8 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -26,9 +26,6 @@
   :group 'company
   :type 'function)
 
-(defvar company-semantic-context-regexp
-  "\\(->\\|\\.\\|\\_<\\)\\(\\(\\s_\\|\\sw\\)+\\_>\\=\\)")
-
 (defun company-semantic-doc-or-summary (tag)
   (or (semantic-documentation-for-tag tag)
       (funcall semantic-idle-summary-function tag nil t)))
@@ -70,7 +67,7 @@
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
                   (semantic-active-p)
                   (not (company-in-string-or-comment))
-                  (or (company-grab company-semantic-context-regexp 2) "")))
+                  (company-grab-symbol)))
     ('candidates (or (company-semantic-completions arg)
                      (mapcar 'semantic-tag-name
                              (semantic-analyze-find-tags-by-prefix arg))))
diff --git a/company-xcode.el b/company-xcode.el
index c4d9ee3..8e068ad 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -51,9 +51,6 @@ valid in most contexts."
               (const "Type") (const "Union") (const "Variable")
               (const "Function")))
 
-(defvar company-xcode-symbol-regexp
-  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
-
 (defvar company-xcode-project 'unknown)
 (make-variable-buffer-local 'company-xcode-project)
 
@@ -104,7 +101,7 @@ valid in most contexts."
     ('prefix (and company-xcode-xcodeindex-executable
                   (not (company-in-string-or-comment))
                   (company-xcode-tags)
-                  (or (company-grab company-xcode-symbol-regexp) "")))
+                  (company-grab-symbol)))
     ('candidates (let ((completion-ignore-case nil))
                    (all-completions arg (company-xcode-tags))))))
 
diff --git a/company.el b/company.el
index c064b3d..ad86054 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Performance enhancements.
+;;
 ;; 2009-04-12 (0.3)
 ;;    Added `company-begin-commands' option.
 ;;    Added abbrev, tempo and Xcode back-ends.
@@ -512,10 +514,25 @@ keymap during active completions (`company-active-map'):
 
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun company-grab (regexp &optional expression)
-  (when (looking-back regexp)
+(defun company-grab (regexp &optional expression limit)
+  (when (looking-back regexp limit)
     (or (match-string-no-properties (or expression 0)) "")))
 
+(defun company-grab-line (regexp &optional expression)
+  (company-grab regexp expression (point-at-bol)))
+
+(defun company-grab-symbol ()
+  (if (looking-at "\\_>")
+      (buffer-substring (point) (save-excursion (skip-syntax-backward "w_")
+                                                (point)))
+    ""))
+
+(defun company-grab-word ()
+  (if (looking-at "\\>")
+      (buffer-substring (point) (save-excursion (skip-syntax-backward "w")
+                                                (point)))
+    ""))
+
 (defun company-in-string-or-comment (&optional point)
   (let ((pos (syntax-ppss)))
     (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))

commit 4f78548ad62f25816529bb117c9721108daa3f1c
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 12 10:34:25 2009 +0200

    Bumped version to 0.3.

diff --git a/company-abbrev.el b/company-abbrev.el
index b34a821..5925977 100644
--- a/company-abbrev.el
+++ b/company-abbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-css.el b/company-css.el
index 23c2802..dcb58a1 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 64e55a2..e0a4a90 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index bd03ea6..d902c4d 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index b010423..820ffee 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index b81625a..cdb8bf1 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index d27d103..e9aca67 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index 3096148..fbbeda3 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 2855be6..aad2fc2 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 6012a1b..c649c3c 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index c6d5229..e1cfbda 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-tempo.el b/company-tempo.el
index 70db986..27c05ad 100644
--- a/company-tempo.el
+++ b/company-tempo.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-xcode.el b/company-xcode.el
index 1280c10..c4d9ee3 100644
--- a/company-xcode.el
+++ b/company-xcode.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.1.
+;; This file is part of company 0.3.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index 87b2b93..c064b3d 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.2.1
+;; Version: 0.3
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-12 (0.3)
 ;;    Added `company-begin-commands' option.
 ;;    Added abbrev, tempo and Xcode back-ends.
 ;;    Back-ends are now interactive.  You can start them with M-x backend-name.

commit 7628f1be78eefdafa14d2aa9b0f549ccd8c2e7d3
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 13 09:12:18 2009 +0200

    Fixed byte-compile warning.

diff --git a/company-elisp.el b/company-elisp.el
index 5336d83..bd03ea6 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -19,6 +19,7 @@
 
 (require 'company)
 (eval-when-compile (require 'cl))
+(require 'help-mode)
 
 (defcustom company-elisp-detect-function-context t
   "*If enabled, offer lisp functions only in appropriate contexts.

commit 650bbd4001e9a11f2586f8e3a148946e2fc5e346
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 13 08:27:04 2009 +0200

    Added company-begin-commands option.

diff --git a/company.el b/company.el
index 6558067..87b2b93 100644
--- a/company.el
+++ b/company.el
@@ -69,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-begin-commands' option.
 ;;    Added abbrev, tempo and Xcode back-ends.
 ;;    Back-ends are now interactive.  You can start them with M-x backend-name.
 ;;    Added `company-begin-with' for starting company from elisp-code.
@@ -369,6 +370,17 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
                  (const :tag "immediate (t)" t)
                  (number :tag "seconds")))
 
+(defcustom company-begin-commands t
+  "*A list of commands following which company will start completing.
+If this is t, it will complete after any command.  See `company-idle-delay'.
+
+Alternatively any command with a non-nil 'company-begin property is treated as
+if it was on this list."
+  :group 'company
+  :type '(choice (const :tag "Any command" t)
+                 (const :tag "Self insert command" '(self-insert-command))
+                 (repeat :tag "Commands" function)))
+
 (defcustom company-show-numbers nil
   "*If enabled, show quick-access numbers for the first ten candidates."
   :group 'company
@@ -563,6 +575,9 @@ keymap during active completions (`company-active-map'):
 
 (defsubst company-should-complete (prefix)
   (and (eq company-idle-delay t)
+       (or (eq t company-begin-commands)
+           (memq this-command company-begin-commands)
+           (and (symbolp this-command) (get this-command 'company-begin)))
        (not (and transient-mark-mode mark-active))
        (>= (length prefix) company-minimum-prefix-length)))
 
@@ -657,7 +672,8 @@ keymap during active completions (`company-active-map'):
   (and company-mode
        (not company-candidates)
        (let ((company-idle-delay t)
-             (company-minimum-prefix-length 0))
+             (company-minimum-prefix-length 0)
+             (company-begin-commands t))
          (setq company--explicit-action t)
          (company-begin)))
   ;; Return non-nil if active.

commit a1de19c8b458426a71dd22c9118ecf771c03cfb8
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 12 09:37:33 2009 +0200

    Completing common should not call company-finish unless unique.

diff --git a/company.el b/company.el
index 086c021..6558067 100644
--- a/company.el
+++ b/company.el
@@ -1064,8 +1064,8 @@ followed by `company-search-kill-others' after each 
input."
   "Complete the common part of all candidates."
   (interactive)
   (when (company-manual-begin)
-    (if (equal company-common (car company-candidates))
-        ;; for success message
+    (if (and (not (cdr company-candidates))
+             (equal company-common (car company-candidates)))
         (company-complete-selection)
       (insert (company-strip-prefix company-common)))))
 

commit 6a5188b46e51f9476cb8d700bf8143db2206a40e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 11 22:05:28 2009 +0200

    Added Xcode back-end.

diff --git a/company-xcode.el b/company-xcode.el
new file mode 100644
index 0000000..1280c10
--- /dev/null
+++ b/company-xcode.el
@@ -0,0 +1,113 @@
+;;; company-xcode.el --- a company-mode completion back-end for Xcode projects
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.2.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defcustom company-xcode-xcodeindex-executable (executable-find "xcodeindex")
+  "*Location of xcodeindex executable"
+  :group 'company-xcode
+  :type 'file)
+
+(defvar company-xcode-tags nil)
+
+(defun company-xcode-reset ()
+  "Reset the cached tags."
+  (interactive)
+  (setq company-xcode-tags nil))
+
+(defcustom company-xcode-types
+  '("Class" "Const" "Constant" "Enum" "Macro" "Modeled Class" "Structure"
+    "Type" "Union" "Function")
+  "*The types of symbols offered by `company-xcode'
+No context-enabled completion is available.  Types like methods will be
+offered regardless of whether the class supports them.  The defaults should be
+valid in most contexts."
+  :set (lambda (variable value)
+         (set variable value)
+         (company-xcode-reset))
+  :group 'company-xcode
+  :type '(set (const "Category") (const "Class") (const "Class Method")
+              (const "Const") (const "Constant") (const "Enum") (const "Field")
+              (const "Instance Method") (const "Instance Variables")
+              (const "Macro") (const "Modeled Class") (const "Modeled Method")
+              (const "Property") (const "Protocol") (const "Structure")
+              (const "Type") (const "Union") (const "Variable")
+              (const "Function")))
+
+(defvar company-xcode-symbol-regexp
+  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
+
+(defvar company-xcode-project 'unknown)
+(make-variable-buffer-local 'company-xcode-project)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-xcode-fetch (project-bundle)
+  (setq project-bundle (directory-file-name project-bundle))
+  (message "Retrieving dump from %s..." project-bundle)
+  (with-temp-buffer
+    (let ((default-directory (file-name-directory project-bundle)))
+      (call-process company-xcode-xcodeindex-executable nil (current-buffer)
+                    nil "dump" "-project"
+                    (file-name-nondirectory project-bundle) "-quiet")
+      (goto-char (point-min))
+      (let ((regexp (concat "^\\([^\t\n]*\\)\t[^\t\n]*\t"
+                            (regexp-opt company-xcode-types)
+                            "\t[^\t\n]*\t[^\t\n]*"))
+            candidates)
+        (while (re-search-forward regexp nil t)
+          (add-to-list 'candidates (match-string 1)))
+        (message "Retrieving dump from %s...done" project-bundle)
+        candidates))))
+
+(defun company-xcode-find-project ()
+  (let ((dir (if buffer-file-name
+                 (file-name-directory buffer-file-name)
+               (expand-file-name default-directory)))
+        file)
+    (while (not (or file (equal dir "/")))
+      (setq file (car (directory-files dir t ".xcodeproj\\'" t))
+            dir (file-name-directory (directory-file-name dir))))
+    file))
+
+(defun company-xcode-tags ()
+  (when (eq company-xcode-project 'unknown)
+    (setq company-xcode-project (company-xcode-find-project)))
+  (when company-xcode-project
+    (cdr (or (assoc company-xcode-project company-xcode-tags)
+             (car (push (cons company-xcode-project
+                              (company-xcode-fetch company-xcode-project))
+                        company-xcode-tags))))))
+;;;###autoload
+(defun company-xcode (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for Xcode projects."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-xcode))
+    ('prefix (and company-xcode-xcodeindex-executable
+                  (not (company-in-string-or-comment))
+                  (company-xcode-tags)
+                  (or (company-grab company-xcode-symbol-regexp) "")))
+    ('candidates (let ((completion-ignore-case nil))
+                   (all-completions arg (company-xcode-tags))))))
+
+
+(provide 'company-xcode)
+;;; company-xcode.el ends here
diff --git a/company.el b/company.el
index c7a34d5..086c021 100644
--- a/company.el
+++ b/company.el
@@ -69,7 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
-;;    Added abbrev and tempo back-ends.
+;;    Added abbrev, tempo and Xcode back-ends.
 ;;    Back-ends are now interactive.  You can start them with M-x backend-name.
 ;;    Added `company-begin-with' for starting company from elisp-code.
 ;;    Added hooks.
@@ -234,8 +234,9 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-gtags company-etags
-                              company-oddmuse company-files company-dabbrev)
+                              company-semantic company-xcode company-gtags
+                              company-etags company-oddmuse company-files
+                              company-dabbrev)
   "*The list of active back-ends (completion engines).
 Each back-end is a function that takes a variable number of arguments.
 The first argument is the command requested from the back-end.  It is one

commit ac08ea40a32b8ac7dd946ae72326d1e31468dd9b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Apr 11 22:05:09 2009 +0200

    Enable semantic back-end only in suitable buffers.

diff --git a/company-semantic.el b/company-semantic.el
index 8ddcc19..c6d5229 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -68,6 +68,7 @@
   (case command
     ('interactive (company-begin-backend 'company-semantic))
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
+                  (semantic-active-p)
                   (not (company-in-string-or-comment))
                   (or (company-grab company-semantic-context-regexp 2) "")))
     ('candidates (or (company-semantic-completions arg)

commit e672f69dc1588bac311978f494e5e17326672047
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 10 10:36:31 2009 +0200

    Added manual-only option for company-auto-complete.

diff --git a/company.el b/company.el
index ffaf8dc..c7a34d5 100644
--- a/company.el
+++ b/company.el
@@ -319,19 +319,29 @@ This can be overridden by the back-end, if it returns t 
or 'never to
                         'company-explicit-action-p)
                  (const :tag "On" t)))
 
-(defcustom company-auto-complete '(?\  ?\( ?\) ?. ?\" ?$ ?\' ?< ?| ?!)
+(defcustom company-auto-complete 'company-explicit-action-p
+  "Determines when to auto-complete.
+If this is enabled, all characters from `company-auto-complete-chars' complete
+the selected completion.  This can also be a function."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (function :tag "Predicate function")
+                 (const :tag "On, if user interaction took place"
+                        'company-explicit-action-p)
+                 (const :tag "On" t)))
+
+(defcustom company-auto-complete-chars '(?\  ?\( ?\) ?. ?\" ?$ ?\' ?< ?| ?!)
   "Determines which characters trigger an automatic completion.
-If this is a function, it is called with the new input and should return 
non-nil
-if company should auto-complete.
+See `company-auto-complete'.  If this is a string, each string character causes
+completion.  If it is a list of syntax description characters (see
+`modify-char-syntax'), all characters with that syntax auto-complete.
 
-If this is a string, all characters in that string will complete automatically.
+This can also be a function, which is called with the new input and should
+return non-nil if company should auto-complete.
 
-A list of characters represent the syntax (see `modify-syntax-entry') of
-characters that complete automatically."
+A character that is part of a valid candidate never starts auto-completion."
   :group 'company
-  :type '(choice (const :tag "Off" nil)
-                 (function :tag "Predicate function")
-                 (string :tag "Characters")
+  :type '(choice (string :tag "Characters")
                  (set :tag "Syntax"
                       (const :tag "Whitespace" ?\ )
                       (const :tag "Symbol" ?_)
@@ -346,7 +356,8 @@ characters that complete automatically."
                       (const :tag "Comment ender." ?>)
                       (const :tag "Character-quote." ?/)
                       (const :tag "Generic string fence." ?|)
-                      (const :tag "Generic comment fence." ?!))))
+                      (const :tag "Generic comment fence." ?!))
+                 (function :tag "Predicate function")))
 
 (defcustom company-idle-delay .7
   "*The idle delay in seconds until automatic completions starts.
@@ -671,11 +682,14 @@ keymap during active completions (`company-active-map'):
   "Return non-nil, if input starts with punctuation or parentheses."
   (and (> end beg)
        (if (functionp company-auto-complete)
-           (funcall company-auto-complete (buffer-substring beg end))
-         (if (consp company-auto-complete)
-             (memq (char-syntax (char-after beg)) company-auto-complete)
+           (funcall company-auto-complete)
+         company-auto-complete)
+       (if (functionp company-auto-complete-chars)
+           (funcall company-auto-complete-chars (buffer-substring beg end))
+         (if (consp company-auto-complete-chars)
+             (memq (char-syntax (char-after beg)) company-auto-complete-chars)
            (string-match (buffer-substring beg (1+ beg))
-                         company-auto-complete)))))
+                         company-auto-complete-chars)))))
 
 (defun company-continue ()
   (when company-candidates

commit 1637c4e388ded0e019225d53fed3e6bbefd43bde
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 10 10:08:42 2009 +0200

    Added tempo back-end.

diff --git a/company-tempo.el b/company-tempo.el
new file mode 100644
index 0000000..70db986
--- /dev/null
+++ b/company-tempo.el
@@ -0,0 +1,55 @@
+;;; company-tempo.el --- a company-mode completion back-end for tempo
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.2.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+(require 'tempo)
+
+(defsubst company-tempo-lookup (match)
+  (cdr (assoc match (tempo-build-collection))))
+
+(defun company-tempo-insert (match)
+  "Replace MATCH with the expanded tempo template."
+  (search-backward match)
+  (goto-char (match-beginning 0))
+  (replace-match "")
+  (call-interactively (company-tempo-lookup match)))
+
+(defsubst company-tempo-meta (match)
+  (let ((templ (company-tempo-lookup match))
+        doc)
+    (and templ
+         (setq doc (documentation templ t))
+         (car (split-string doc "\n" t)))))
+
+;;;###autoload
+(defun company-tempo (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for tempo."
+  (interactive (list 'interactive))
+  (case command
+    ('interactive (company-begin-backend 'company-tempo
+                                         'company-tempo-insert))
+    ('prefix (or (car (tempo-find-match-string tempo-match-finder)) ""))
+    ('candidates (all-completions arg (tempo-build-collection)))
+    ('meta (company-tempo-meta arg))
+    ('require-match t)
+    ('sorted t)))
+
+(provide 'company-tempo)
+;;; company-tempo.el ends here
diff --git a/company.el b/company.el
index d63db9b..ffaf8dc 100644
--- a/company.el
+++ b/company.el
@@ -69,7 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
-;;    Added abbrev back-end.
+;;    Added abbrev and tempo back-ends.
 ;;    Back-ends are now interactive.  You can start them with M-x backend-name.
 ;;    Added `company-begin-with' for starting company from elisp-code.
 ;;    Added hooks.

commit 5a3f881ea489ff202135f6c90ec9fa87eedee86d
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Apr 13 10:20:24 2009 +0200

    Added abbrev back-end.

diff --git a/company-abbrev.el b/company-abbrev.el
new file mode 100644
index 0000000..b34a821
--- /dev/null
+++ b/company-abbrev.el
@@ -0,0 +1,43 @@
+;;; company-abbrev.el --- a company-mode completion back-end for abbrev
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company 0.2.1.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+(require 'abbrev)
+
+(defun company-abbrev-insert (match)
+  "Replace MATCH with the expanded abbrev."
+  (expand-abbrev))
+
+;;;###autoload
+(defun company-abbrev (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for abbrev."
+  (interactive (list 'interactive))
+  (case command
+        ('interactive (company-begin-backend 'company-abbrev
+                                             'company-abbrev-insert))
+        ('prefix (or (company-grab "\\_<\\(\\sw\\|\\s_\\)+\\_>") ""))
+        ('candidates (nconc
+                      (delete "" (all-completions arg global-abbrev-table))
+                      (delete "" (all-completions arg local-abbrev-table))))
+        ('meta (abbrev-expansion arg))
+        ('require-match t)))
+
+(provide 'company-abbrev)
+;;; company-abbrev.el ends here
diff --git a/company.el b/company.el
index d73503b..d63db9b 100644
--- a/company.el
+++ b/company.el
@@ -39,6 +39,10 @@
 ;; Enable company-mode with M-x company-mode.  For further information look at
 ;; the documentation for `company-mode' (C-h f company-mode RET)
 ;;
+;; If you want to start a specific back-end, call it interactively or use
+;; `company-begin-backend'.  For example:
+;; M-x company-abbrev will prompt for and insert an abbrev.
+;;
 ;; To write your own back-end, look at the documentation for 
`company-backends'.
 ;; Here is a simple example completing "foo":
 ;;
@@ -65,6 +69,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added abbrev back-end.
 ;;    Back-ends are now interactive.  You can start them with M-x backend-name.
 ;;    Added `company-begin-with' for starting company from elisp-code.
 ;;    Added hooks.

commit 715d9f8502473b20049b00554e425e844afb84ee
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Apr 10 10:28:03 2009 +0200

    Added interactive form for back-ends.

diff --git a/company-css.el b/company-css.el
index 6d811b7..23c2802 100644
--- a/company-css.el
+++ b/company-css.el
@@ -271,9 +271,12 @@ Returns \"\" if no property found, but feasible at this 
position."
   "\\_<\\([[:alpha:]-]+\\):\\(?:[^};]*[[:space:]]+\\)?\\([^};]*\\_>\\|\\)\\="
   "A regular expression matching CSS tags")
 
+;;;###autoload
 (defun company-css (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `css-mode'."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-css))
     ('prefix (and (eq major-mode 'css-mode)
                   (or (company-grab company-css-tag-regexp 1)
                       (company-grab company-css-pseudo-regexp 1)
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 2a7c1b4..64e55a2 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -29,9 +29,12 @@
         (dabbrev--goto-start-of-abbrev)
         (buffer-substring-no-properties (point) end)))))
 
+;;;###autoload
 (defun company-dabbrev (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `dabbrev-completion'."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-dabbrev))
     ('prefix (company-grab-dabbrev-prefix))
     ('candidates (let ((dabbrev-check-other-buffers))
                    (dabbrev--reset-global-variables)
diff --git a/company-elisp.el b/company-elisp.el
index 112fd11..5336d83 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -104,9 +104,12 @@ Functions are offered for completion only after ' and \(."
          (string-match ".*$" doc)
          (match-string 0 doc))))
 
+;;;###autoload
 (defun company-elisp (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `emacs-lisp-mode'."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-elisp))
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
     ('candidates (company-elisp-candidates arg))
diff --git a/company-etags.el b/company-etags.el
index 5f2280f..b010423 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -56,9 +56,12 @@ buffer automatically."
           (setq company-etags-buffer-table (company-etags-find-table))
         company-etags-buffer-table)))
 
+;;;###autoload
 (defun company-etags (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for etags."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-etags))
     ('prefix (and (memq major-mode company-etags-modes)
                   (not (company-in-string-or-comment))
                   (require 'etags nil t)
diff --git a/company-files.el b/company-files.el
index 4ae2d07..b81625a 100644
--- a/company-files.el
+++ b/company-files.el
@@ -56,9 +56,12 @@
       (setq company-files-completion-cache (cons dir (nreverse candidates))))
     (cdr company-files-completion-cache)))
 
+;;;###autoload
 (defun company-files (command &optional arg &rest ignored)
   "a `company-mode' completion back-end existing file names."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-files))
     ('prefix (company-files-grab-existing-name))
     ('candidates (company-files-complete arg))
     ('location (cons (dired-noselect
diff --git a/company-gtags.el b/company-gtags.el
index d3b429a..d27d103 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -68,9 +68,12 @@
           (cons (expand-file-name (match-string 2))
                 (string-to-number (match-string 1)))))))
 
+;;;###autoload
 (defun company-gtags (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for GNU Global."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-gtags))
     ('prefix (and (memq major-mode company-gtags-modes)
                   (not (company-in-string-or-comment))
                   (company-gtags-available)
diff --git a/company-ispell.el b/company-ispell.el
index 0bf68c2..3096148 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -41,9 +41,12 @@ If nil, use `ispell-complete-word-dict'."
        (setq company-ispell-available nil))))
   company-ispell-available)
 
+;;;###autoload
 (defun company-ispell (command &optional arg &rest ignored)
   "A `company-mode' completion back-end using ispell."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-ispell))
     ('prefix (when (company-ispell-available)
                (company-grab "\\<\\w+\\>")))
     ('candidates (lookup-words arg (or company-ispell-dictionary
diff --git a/company-nxml.el b/company-nxml.el
index d9d3057..2855be6 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -102,9 +102,12 @@
                           (all-completions arg
                            (rng-match-possible-value-strings))))))))
 
+;;;###autoload
 (defun company-nxml (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `nxml-mode'."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-nxml))
     ('prefix (or (company-nxml-tag 'prefix)
                  (company-nxml-attribute 'prefix)
                  (company-nxml-attribute-value 'prefix)))
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 67ab0d3..6012a1b 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -32,9 +32,12 @@
     ('oddmuse-mode (with-no-warnings
                      (oddmuse-make-completion-table oddmuse-wiki)))))
 
+;;;###autoload
 (defun company-oddmuse (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `oddmuse-mode'."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-oddmuse))
     ('prefix (let ((case-fold-search nil))
                (and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
                     (looking-back company-oddmuse-link-regexp (point-at-bol))
diff --git a/company-semantic.el b/company-semantic.el
index 9a9e038..8ddcc19 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -61,9 +61,12 @@
           (context (semantic-analyze-current-context)))
       (all-completions prefix (semantic-ia-get-completions context (point))))))
 
+;;;###autoload
 (defun company-semantic (command &optional arg &rest ignored)
   "A `company-mode' completion back-end using CEDET Semantic."
+  (interactive (list 'interactive))
   (case command
+    ('interactive (company-begin-backend 'company-semantic))
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
                   (not (company-in-string-or-comment))
                   (or (company-grab company-semantic-context-regexp 2) "")))
diff --git a/company.el b/company.el
index 2ebaa66..d73503b 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Back-ends are now interactive.  You can start them with M-x backend-name.
 ;;    Added `company-begin-with' for starting company from elisp-code.
 ;;    Added hooks.
 ;;    Added `company-require-match' and `company-auto-complete' options.
@@ -99,6 +100,7 @@
 (add-to-list 'debug-ignored-errors "^No \\(document\\|loc\\)ation available$")
 (add-to-list 'debug-ignored-errors "^Company not ")
 (add-to-list 'debug-ignored-errors "^No candidate number ")
+(add-to-list 'debug-ignored-errors "^Cannot complete at point$")
 
 (defgroup company nil
   "Extensible inline text completion mechanism"
@@ -267,7 +269,8 @@ user that choice with `company-require-match'.  Return 
value 'never overrides
 that option the other way around.
 
 The back-end should return nil for all commands it does not support or
-does not know about."
+does not know about.  It should also be callable interactively and use
+`company-begin-backend' to start itself in that case."
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
@@ -407,7 +410,8 @@ Completions can be searched with 
`company-search-candidates' or
 inactive, as well.
 
 The completion data is retrieved using `company-backends' and displayed using
-`company-frontends'.
+`company-frontends'.  If you want to start a specific back-end, call it
+interactively or use `company-begin-backend'.
 
 regular keymap (`company-mode-map'):
 
@@ -1159,6 +1163,11 @@ when the selection has been changed, the selected 
candidate is completed."
 
 (defun company-begin-backend (backend &optional callback)
   "Start a completion at point using BACKEND."
+  (interactive (let ((val (completing-read "Company back-end: "
+                                           obarray
+                                           'functionp nil "company-")))
+                 (when val
+                   (list (intern val)))))
   (when callback
     (setq company-callback
           `(lambda (completion)
@@ -1167,7 +1176,9 @@ when the selection has been changed, the selected 
candidate is completed."
     (add-hook 'company-completion-cancelled-hook 'company-remove-callback nil 
t)
     (add-hook 'company-completion-finished-hook company-callback nil t))
   (setq company-backend backend)
-  (company-manual-begin))
+  ;; Return non-nil if active.
+  (or (company-manual-begin)
+      (error "Cannot complete at point")))
 
 (defun company-begin-with (candidates
                            &optional prefix-length require-match callback)

commit a24a6492ffdf0880d32d5f8daef2114715155414
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 10:44:39 2009 +0200

    Added `company-begin-with' for starting company from elisp-code.

diff --git a/company.el b/company.el
index 19fafc7..2ebaa66 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-begin-with' for starting company from elisp-code.
 ;;    Added hooks.
 ;;    Added `company-require-match' and `company-auto-complete' options.
 ;;
@@ -420,11 +421,12 @@ keymap during active completions (`company-active-map'):
         (add-hook 'pre-command-hook 'company-pre-command nil t)
         (add-hook 'post-command-hook 'company-post-command nil t)
         (dolist (backend company-backends)
-          (unless (fboundp backend)
-            (ignore-errors (require backend nil t)))
-          (unless (fboundp backend)
-            (message "Company back-end '%s' could not be initialized"
-                     backend))))
+          (when (symbolp backend)
+            (unless (fboundp backend)
+              (ignore-errors (require backend nil t)))
+            (unless (fboundp backend)
+              (message "Company back-end '%s' could not be initialized"
+                       backend)))))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
     (company-cancel)
@@ -708,8 +710,11 @@ keymap during active completions (`company-active-map'):
     (company-continue)
     (unless company-candidates
       (let (prefix)
-        (dolist (backend company-backends)
-          (when (and (fboundp backend)
+        (dolist (backend (if company-backend
+                             ;; prefer manual override
+                             (list company-backend)
+                           (cons company-backend company-backends)))
+          (when (and (functionp backend)
                      (setq prefix (funcall backend 'prefix)))
             (setq company-backend backend)
             (when (company-should-complete prefix)
@@ -1143,6 +1148,49 @@ when the selection has been changed, the selected 
candidate is completed."
         (set-window-start nil (point))))))
 (put 'company-show-location 'company-keep t)
 
+;;; package functions 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-callback nil)
+(make-variable-buffer-local 'company-callback)
+
+(defun company-remove-callback (&optional ignored)
+  (remove-hook 'company-completion-finished-hook company-callback t)
+  (remove-hook 'company-completion-cancelled-hook 'company-remove-callback t))
+
+(defun company-begin-backend (backend &optional callback)
+  "Start a completion at point using BACKEND."
+  (when callback
+    (setq company-callback
+          `(lambda (completion)
+             (funcall ',callback completion)
+             (company-remove-callback)))
+    (add-hook 'company-completion-cancelled-hook 'company-remove-callback nil 
t)
+    (add-hook 'company-completion-finished-hook company-callback nil t))
+  (setq company-backend backend)
+  (company-manual-begin))
+
+(defun company-begin-with (candidates
+                           &optional prefix-length require-match callback)
+  "Start a completion at point.
+CANDIDATES is the list of candidates to use and PREFIX-LENGTH is the length of
+the prefix that already is in the buffer before point.  It defaults to 0.
+
+CALLBACK is a function called with the selected result if the user successfully
+completes the input.
+
+Example:
+\(company-begin-with '\(\"foo\" \"foobar\" \"foobarbaz\"\)\)"
+  (company-begin-backend
+   (let ((start (- (point) (or prefix-length 0))))
+     `(lambda (command &optional arg &rest ignored)
+        (case command-history
+          ('prefix (message "prefix %s" (buffer-substring ,start (point)))
+                   (when (>= (point) ,start)
+                     (buffer-substring ,start (point))))
+          ('candidates (all-completions arg ',candidates))
+          ('require-match ,require-match))))
+   callback))
+
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-pseudo-tooltip-overlay nil)

commit fbaa0e3206382f98495f0b857594d46ddb422fb9
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 8 13:13:07 2009 +0200

    Added company-auto-complete option.

diff --git a/company.el b/company.el
index f2c3657..19fafc7 100644
--- a/company.el
+++ b/company.el
@@ -66,7 +66,7 @@
 ;;; Change Log:
 ;;
 ;;    Added hooks.
-;;    Added `company-require-match' option.
+;;    Added `company-require-match' and `company-auto-complete' options.
 ;;
 ;; 2009-04-05 (0.2.1)
 ;;    Improved Emacs Lisp back-end behavior for local variables.
@@ -302,7 +302,7 @@ The hook is called with the selected candidate as an 
argument."
 This can be a function do determine if a match is required.
 
 This can be overridden by the back-end, if it returns t or 'never to
-'require-match."
+'require-match.  `company-auto-complete' also takes precedence over this."
   :group 'company
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
@@ -310,6 +310,35 @@ This can be overridden by the back-end, if it returns t or 
'never to
                         'company-explicit-action-p)
                  (const :tag "On" t)))
 
+(defcustom company-auto-complete '(?\  ?\( ?\) ?. ?\" ?$ ?\' ?< ?| ?!)
+  "Determines which characters trigger an automatic completion.
+If this is a function, it is called with the new input and should return 
non-nil
+if company should auto-complete.
+
+If this is a string, all characters in that string will complete automatically.
+
+A list of characters represent the syntax (see `modify-syntax-entry') of
+characters that complete automatically."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (function :tag "Predicate function")
+                 (string :tag "Characters")
+                 (set :tag "Syntax"
+                      (const :tag "Whitespace" ?\ )
+                      (const :tag "Symbol" ?_)
+                      (const :tag "Opening parentheses" ?\()
+                      (const :tag "Closing parentheses" ?\))
+                      (const :tag "Word constituent" ?w)
+                      (const :tag "Punctuation." ?.)
+                      (const :tag "String quote." ?\")
+                      (const :tag "Paired delimiter." ?$)
+                      (const :tag "Expression quote or prefix operator." ?\')
+                      (const :tag "Comment starter." ?<)
+                      (const :tag "Comment ender." ?>)
+                      (const :tag "Character-quote." ?/)
+                      (const :tag "Generic string fence." ?|)
+                      (const :tag "Generic comment fence." ?!))))
+
 (defcustom company-idle-delay .7
   "*The idle delay in seconds until automatic completions starts.
 A value of nil means never complete automatically, t means complete
@@ -623,6 +652,20 @@ keymap during active completions (`company-active-map'):
                (eq company-require-match t))
              (not (eq backend-value 'never))))))
 
+(defun company-punctuation-p (input)
+  "Return non-nil, if input starts with punctuation or parentheses."
+  (memq (char-syntax (string-to-char input)) '(?. ?\( ?\))))
+
+(defun company-auto-complete-p (beg end)
+  "Return non-nil, if input starts with punctuation or parentheses."
+  (and (> end beg)
+       (if (functionp company-auto-complete)
+           (funcall company-auto-complete (buffer-substring beg end))
+         (if (consp company-auto-complete)
+             (memq (char-syntax (char-after beg)) company-auto-complete)
+           (string-match (buffer-substring beg (1+ beg))
+                         company-auto-complete)))))
+
 (defun company-continue ()
   (when company-candidates
     (when (funcall company-backend 'no-cache company-prefix)
@@ -640,18 +683,23 @@ keymap during active completions (`company-active-map'):
                              (setq company-prefix new-prefix)
                              (company-update-candidates c)
                              t)))))
-        (if (not (and (company-incremental-p company-prefix new-prefix)
-                      (company-require-match-p)))
-            (progn
-              (when (equal company-prefix (car company-candidates))
-                ;; cancel, but last input was actually success
-                (company-cancel company-prefix))
+        (if (company-auto-complete-p company-point (point))
+            (save-excursion
+              (goto-char company-point)
+              (company-complete-selection)
               (setq company-candidates nil))
-          (backward-delete-char (length new-prefix))
-          (insert company-prefix)
-          (ding)
-          (message "Matching input is required")
-          company-candidates)))))
+          (if (not (and (company-incremental-p company-prefix new-prefix)
+                        (company-require-match-p)))
+              (progn
+                (when (equal company-prefix (car company-candidates))
+                  ;; cancel, but last input was actually success
+                  (company-cancel company-prefix))
+                (setq company-candidates nil))
+            (backward-delete-char (length new-prefix))
+            (insert company-prefix)
+            (ding)
+            (message "Matching input is required")))
+        company-candidates))))
 
 (defun company-begin ()
   (if (or buffer-read-only overriding-terminal-local-map overriding-local-map)

commit 899e976ba9d0812d346519d9546cfe568c1d6ed5
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 9 13:06:18 2009 +0200

    Don't start when region is active.

diff --git a/company.el b/company.el
index fa722e2..f2c3657 100644
--- a/company.el
+++ b/company.el
@@ -511,6 +511,7 @@ keymap during active completions (`company-active-map'):
 
 (defsubst company-should-complete (prefix)
   (and (eq company-idle-delay t)
+       (not (and transient-mark-mode mark-active))
        (>= (length prefix) company-minimum-prefix-length)))
 
 (defsubst company-call-frontends (command)

commit bdcdad59c13f5645b38c24e9a4c1ebab781d6b6d
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 8 22:01:39 2009 +0200

    Added keybinding for company-abort.

diff --git a/company.el b/company.el
index 56b0a75..fa722e2 100644
--- a/company.el
+++ b/company.el
@@ -336,6 +336,8 @@ The work-around consists of adding a newline.")
 
 (defvar company-active-map
   (let ((keymap (make-sparse-keymap)))
+    (define-key keymap "\e\e\e" 'company-abort)
+    (define-key keymap "\C-g" 'company-abort)
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap (kbd "<down>") 'company-select-next)
@@ -712,6 +714,7 @@ keymap during active completions (`company-active-map'):
   (company-enable-overriding-keymap nil))
 
 (defun company-abort ()
+  (interactive)
   (company-cancel t)
   ;; Don't start again, unless started manually.
   (setq company-point (point)))

commit 0e685a00faf3a288ba1e1f988064b7d44947a0b3
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Apr 8 20:18:07 2009 +0200

    Make sure hooks are called when finishing by character input.

diff --git a/company.el b/company.el
index 464ac68..56b0a75 100644
--- a/company.el
+++ b/company.el
@@ -557,26 +557,30 @@ keymap during active completions (`company-active-map'):
     (setq company-candidates nil)))
 
 (defun company-calculate-candidates (prefix)
-  (or (cdr (assoc prefix company-candidates-cache))
-      (when company-candidates-cache
-        (let ((len (length prefix))
-              (completion-ignore-case (funcall company-backend 'ignore-case))
-              prev)
-          (dotimes (i len)
-            (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
-                                         company-candidates-cache)))
-              (return (all-completions prefix prev))))))
-      (let ((candidates (funcall company-backend 'candidates prefix)))
-        (when company-candidates-predicate
-          (setq candidates
-                (company-apply-predicate candidates
-                                         company-candidates-predicate)))
-        (unless (funcall company-backend 'sorted)
-          (setq candidates (sort candidates 'string<)))
-        (when (or (cdr candidates)
-                  (not (equal (car candidates) prefix)))
-          ;; Don't start when already completed and unique.
-          candidates))))
+  (let ((candidates
+         (or (cdr (assoc prefix company-candidates-cache))
+             (when company-candidates-cache
+               (let ((len (length prefix))
+                     (completion-ignore-case (funcall company-backend
+                                                      'ignore-case))
+                     prev)
+                 (dotimes (i len)
+                   (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                                company-candidates-cache)))
+                     (return (all-completions prefix prev))))))
+             (let ((c (funcall company-backend 'candidates prefix)))
+               (when company-candidates-predicate
+                 (setq c (company-apply-predicate
+                          c company-candidates-predicate)))
+               (unless (funcall company-backend 'sorted)
+                 (setq c (sort c 'string<)))
+               c))))
+    (if (or (cdr candidates)
+            (not (equal (car candidates) prefix)))
+        ;; Don't start when already completed and unique.
+        candidates
+      ;; Not the right place? maybe when setting?
+      (and company-candidates t))))
 
 (defun company-idle-begin (buf win tick pos)
   (and company-mode
@@ -626,13 +630,20 @@ keymap during active completions (`company-active-map'):
                       (- company-point (length company-prefix)))
                    (or (equal company-prefix new-prefix)
                        (let ((c (company-calculate-candidates new-prefix)))
-                         (when c
-                           (setq company-prefix new-prefix)
-                           (company-update-candidates c)
-                           t))))
+                         ;; t means complete/unique.
+                         (if (eq c t)
+                             (progn (company-cancel new-prefix) t)
+                           (when (consp c)
+                             (setq company-prefix new-prefix)
+                             (company-update-candidates c)
+                             t)))))
         (if (not (and (company-incremental-p company-prefix new-prefix)
                       (company-require-match-p)))
-            (setq company-candidates nil)
+            (progn
+              (when (equal company-prefix (car company-candidates))
+                ;; cancel, but last input was actually success
+                (company-cancel company-prefix))
+              (setq company-candidates nil))
           (backward-delete-char (length new-prefix))
           (insert company-prefix)
           (ding)
@@ -652,7 +663,8 @@ keymap during active completions (`company-active-map'):
             (setq company-backend backend)
             (when (company-should-complete prefix)
               (let ((c (company-calculate-candidates prefix)))
-                (when c
+                ;; t means complete/unique.  We don't start, so no hooks.
+                (when (consp c)
                   (setq company-prefix prefix)
                   (company-update-candidates c)
                   (run-hook-with-args 'company-completion-started-hook

commit 8f896b470297d1395886705b820e77a26271d04d
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 23:02:31 2009 +0200

    Added hooks.

diff --git a/company.el b/company.el
index 827eb3e..464ac68 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added hooks.
 ;;    Added `company-require-match' option.
 ;;
 ;; 2009-04-05 (0.2.1)
@@ -269,6 +270,28 @@ does not know about."
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
+(defvar start-count 0)
+
+(defcustom company-completion-started-hook nil
+  "*Hook run when company starts completing.
+The hook is called with one argument that is non-nil if the completion was
+started manually."
+  :group 'company
+  :type 'hook)
+
+(defcustom company-completion-cancelled-hook nil
+  "*Hook run when company cancels completing.
+The hook is called with one argument that is non-nil if the completion was
+aborted manually."
+  :group 'company
+  :type 'hook)
+
+(defcustom company-completion-finished-hook nil
+  "*Hook run when company successfully completes.
+The hook is called with the selected candidate as an argument."
+  :group 'company
+  :type 'hook)
+
 (defcustom company-minimum-prefix-length 3
   "*The minimum prefix length for automatic completion."
   :group 'company
@@ -550,7 +573,10 @@ keymap during active completions (`company-active-map'):
                                          company-candidates-predicate)))
         (unless (funcall company-backend 'sorted)
           (setq candidates (sort candidates 'string<)))
-        candidates)))
+        (when (or (cdr candidates)
+                  (not (equal (car candidates) prefix)))
+          ;; Don't start when already completed and unique.
+          candidates))))
 
 (defun company-idle-begin (buf win tick pos)
   (and company-mode
@@ -625,9 +651,13 @@ keymap during active completions (`company-active-map'):
                      (setq prefix (funcall backend 'prefix)))
             (setq company-backend backend)
             (when (company-should-complete prefix)
-              (setq company-prefix prefix)
-              (company-update-candidates (company-calculate-candidates prefix))
-              (company-call-frontends 'show))
+              (let ((c (company-calculate-candidates prefix)))
+                (when c
+                  (setq company-prefix prefix)
+                  (company-update-candidates c)
+                  (run-hook-with-args 'company-completion-started-hook
+                                      (company-explicit-action-p))
+                  (company-call-frontends 'show))))
             (return prefix))))))
   (if company-candidates
       (progn
@@ -639,7 +669,7 @@ keymap during active completions (`company-active-map'):
         (company-call-frontends 'update))
     (company-cancel)))
 
-(defun company-cancel ()
+(defun company-cancel (&optional result)
   (and company-added-newline
        (> (point-max) (point-min))
        (let ((tick (buffer-chars-modified-tick)))
@@ -647,6 +677,10 @@ keymap during active completions (`company-active-map'):
          (equal tick company-added-newline))
        ;; Only set unmodified when tick remained the same since insert.
        (set-buffer-modified-p nil))
+  (when company-prefix
+    (if (stringp result)
+        (run-hook-with-args 'company-completion-finished-hook result)
+      (run-hook-with-args 'company-completion-cancelled-hook result)))
   (setq company-added-newline nil
         company-backend nil
         company-prefix nil
@@ -666,7 +700,13 @@ keymap during active completions (`company-active-map'):
   (company-enable-overriding-keymap nil))
 
 (defun company-abort ()
-  (company-cancel)
+  (company-cancel t)
+  ;; Don't start again, unless started manually.
+  (setq company-point (point)))
+
+(defun company-finish (result)
+  (insert (company-strip-prefix result))
+  (company-cancel result)
   ;; Don't start again, unless started manually.
   (setq company-point (point)))
 
@@ -925,14 +965,16 @@ followed by `company-search-kill-others' after each 
input."
   "Complete the selected candidate."
   (interactive)
   (when (company-manual-begin)
-    (insert (company-strip-prefix (nth company-selection company-candidates)))
-    (company-abort)))
+    (company-finish (nth company-selection company-candidates))))
 
 (defun company-complete-common ()
   "Complete the common part of all candidates."
   (interactive)
   (when (company-manual-begin)
-    (insert (company-strip-prefix company-common))))
+    (if (equal company-common (car company-candidates))
+        ;; for success message
+        (company-complete-selection)
+      (insert (company-strip-prefix company-common)))))
 
 (defun company-complete ()
   "Complete the common part of all candidates or the current selection.
@@ -952,8 +994,7 @@ when the selection has been changed, the selected candidate 
is completed."
     (and (< n 1) (> n company-candidates-length)
          (error "No candidate number %d" n))
     (decf n)
-    (insert (company-strip-prefix (nth n company-candidates)))
-    (company-abort)))
+    (company-finish (nth n company-candidates))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 3616bafc7f9ca245e9ac3573ce154361a937bd95
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 15:25:32 2009 +0200

    Uninstall overriding map for good measure when mode is not enabled.
    
    This prevents us from being stuck in the mini-buffer, unable to press enter.

diff --git a/company.el b/company.el
index cfd0571..827eb3e 100644
--- a/company.el
+++ b/company.el
@@ -376,6 +376,11 @@ keymap during active completions (`company-active-map'):
     (company-cancel)
     (kill-local-variable 'company-point)))
 
+(defsubst company-assert-enabled ()
+  (unless company-mode
+    (company-uninstall-map)
+    (error "Company not enabled")))
+
 ;;; keymaps 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-overriding-keymap-bound nil)
@@ -400,8 +405,7 @@ keymap during active completions (`company-active-map'):
           company-overriding-keymap-bound t)))
 
 (defun company-uninstall-map ()
-  (when (and company-overriding-keymap-bound
-             (eq overriding-terminal-local-map company-my-keymap))
+  (when (eq overriding-terminal-local-map company-my-keymap)
     (setq overriding-terminal-local-map company-old-keymap
           company-overriding-keymap-bound nil)))
 
@@ -564,7 +568,7 @@ keymap during active completions (`company-active-map'):
 
 (defun company-manual-begin ()
   (interactive)
-  (unless company-mode (error "Company not enabled"))
+  (company-assert-enabled)
   (and company-mode
        (not company-candidates)
        (let ((company-idle-delay t)
@@ -723,8 +727,7 @@ keymap during active completions (`company-active-map'):
 
 (defun company-search-printing-char ()
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (setq company-search-string
         (concat (or company-search-string "") (string last-command-event))
         company-search-lighter (concat " Search: \"" company-search-string
@@ -738,8 +741,7 @@ keymap during active completions (`company-active-map'):
 (defun company-search-repeat-forward ()
   "Repeat the incremental search in completion candidates forward."
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (let ((pos (company-search company-search-string
                               (cdr (nthcdr company-selection
                                            company-candidates)))))
@@ -750,8 +752,7 @@ keymap during active completions (`company-active-map'):
 (defun company-search-repeat-backward ()
   "Repeat the incremental search in completion candidates backwards."
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (let ((pos (company-search company-search-string
                               (nthcdr (- company-candidates-length
                                          company-selection)
@@ -775,8 +776,7 @@ keymap during active completions (`company-active-map'):
 
 (defun company-filter-printing-char ()
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (company-search-printing-char)
   (company-create-match-predicate)
   (company-call-frontends 'update))
@@ -784,8 +784,7 @@ keymap during active completions (`company-active-map'):
 (defun company-search-kill-others ()
   "Limit the completion candidates to the ones matching the search string."
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (company-create-match-predicate)
   (company-search-mode 0)
   (company-call-frontends 'update))
@@ -793,15 +792,13 @@ keymap during active completions (`company-active-map'):
 (defun company-search-abort ()
   "Abort searching the completion candidates."
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (company-set-selection company-search-old-selection t)
   (company-search-mode 0))
 
 (defun company-search-other-char ()
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-assert-enabled)
   (company-search-mode 0)
   (when last-input-event
     (clear-this-command-keys t)
@@ -857,6 +854,12 @@ Don't start this directly, use `company-search-candidates' 
or
     (kill-local-variable 'company-search-old-selection)
     (company-enable-overriding-keymap company-active-map)))
 
+(defsubst company-search-assert-enabled ()
+  (company-assert-enabled)
+  (unless company-search-mode
+    (company-uninstall-map)
+    (error "Company not in search mode")))
+
 (defun company-search-candidates ()
   "Start searching the completion candidates incrementally.
 
@@ -995,22 +998,20 @@ when the selection has been changed, the selected 
candidate is completed."
 
 (defmacro company-electric (&rest body)
   (declare (indent 0) (debug t))
-  `(if company-mode
-       (when (company-manual-begin)
-         (save-window-excursion
-           (let ((height (window-height))
-                 (row (cdr (posn-col-row (posn-at-point)))))
-             ,@body
-             (and (< (window-height) height)
-                  (< (- (window-height) row 2) company-tooltip-limit)
-                  (recenter (- (window-height) row 2)))
-             (while (eq 'scroll-other-window
-                        (key-binding (vector (list (read-event)))))
-               (call-interactively 'scroll-other-window))
-             (when last-input-event
-               (clear-this-command-keys t)
-               (setq unread-command-events (list last-input-event))))))
-     (error "Company not enabled")))
+  `(when (company-manual-begin)
+     (save-window-excursion
+       (let ((height (window-height))
+             (row (cdr (posn-col-row (posn-at-point)))))
+         ,@body
+         (and (< (window-height) height)
+              (< (- (window-height) row 2) company-tooltip-limit)
+              (recenter (- (window-height) row 2)))
+         (while (eq 'scroll-other-window
+                    (key-binding (vector (list (read-event)))))
+           (call-interactively 'scroll-other-window))
+         (when last-input-event
+           (clear-this-command-keys t)
+           (setq unread-command-events (list last-input-event)))))))
 
 (defun company-show-doc-buffer ()
   "Temporarily show a buffer with the complete documentation for the 
selection."

commit c446ac44239f3736637bc9569d66d9990e20d654
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 14:03:49 2009 +0200

    Combined some ignored error message regular expressions.

diff --git a/company.el b/company.el
index 99c4396..cfd0571 100644
--- a/company.el
+++ b/company.el
@@ -92,14 +92,10 @@
 
 (eval-when-compile (require 'cl))
 
-(add-to-list 'debug-ignored-errors
-             "^Pseudo tooltip frontend cannot be used twice$")
-(add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
+(add-to-list 'debug-ignored-errors "^.* frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
-(add-to-list 'debug-ignored-errors "^No documentation available$")
-(add-to-list 'debug-ignored-errors "^No location available$")
-(add-to-list 'debug-ignored-errors "^Company not enabled$")
-(add-to-list 'debug-ignored-errors "^Company not in search mode$")
+(add-to-list 'debug-ignored-errors "^No \\(document\\|loc\\)ation available$")
+(add-to-list 'debug-ignored-errors "^Company not ")
 (add-to-list 'debug-ignored-errors "^No candidate number ")
 
 (defgroup company nil

commit acd000cd2f669995413f0369ef46a4a7ecd6b584
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 13:55:32 2009 +0200

    Added manual-only option for company-require-match.

diff --git a/company.el b/company.el
index 9da4b47..99c4396 100644
--- a/company.el
+++ b/company.el
@@ -278,14 +278,17 @@ does not know about."
   :group 'company
   :type '(integer :tag "prefix length"))
 
-(defcustom company-require-match nil
+(defcustom company-require-match 'company-explicit-action-p
   "*If enabled, disallow non-matching input.
 This can be a function do determine if a match is required.
+
 This can be overridden by the back-end, if it returns t or 'never to
 'require-match."
   :group 'company
   :type '(choice (const :tag "Off" nil)
                  (function :tag "Predicate function")
+                 (const :tag "On, if user interaction took place"
+                        'company-explicit-action-p)
                  (const :tag "On" t)))
 
 (defcustom company-idle-delay .7
@@ -456,6 +459,10 @@ keymap during active completions (`company-active-map'):
 (defvar company-selection-changed nil)
 (make-variable-buffer-local 'company-selection-changed)
 
+(defvar company--explicit-action nil
+  "Non-nil, if explicit completion took place.")
+(make-variable-buffer-local 'company--explicit-action)
+
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
@@ -467,6 +474,11 @@ keymap during active completions (`company-active-map'):
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
+(defun company-explicit-action-p ()
+  "Return whether explicit completion action was taken by the user."
+  (or company--explicit-action
+      company-selection-changed))
+
 (defsubst company-reformat (candidate)
   ;; company-ispell needs this, because the results are always lower-case
   ;; It's mory efficient to fix it only when they are displayed.
@@ -561,6 +573,7 @@ keymap during active completions (`company-active-map'):
        (not company-candidates)
        (let ((company-idle-delay t)
              (company-minimum-prefix-length 0))
+         (setq company--explicit-action t)
          (company-begin)))
   ;; Return non-nil if active.
   company-candidates)
@@ -570,12 +583,12 @@ keymap during active completions (`company-active-map'):
        (equal old-prefix (substring new-prefix 0 (length old-prefix)))))
 
 (defun company-require-match-p ()
-  (if (functionp company-require-match)
-      (funcall company-require-match)
-    (let ((backend-value (funcall company-backend 'require-match)))
-      (or (eq backend-value t)
-          (and (eq company-require-match t)
-               (not (eq backend-value 'never)))))))
+  (let ((backend-value (funcall company-backend 'require-match)))
+    (or (eq backend-value t)
+        (and (if (functionp company-require-match)
+                 (funcall company-require-match)
+               (eq company-require-match t))
+             (not (eq backend-value 'never))))))
 
 (defun company-continue ()
   (when company-candidates
@@ -644,6 +657,7 @@ keymap during active completions (`company-active-map'):
         company-common nil
         company-selection 0
         company-selection-changed nil
+        company--explicit-action nil
         company-point nil)
   (when company-timer
     (cancel-timer company-timer))

commit e0d75a0b11de1e2da7478e2e3d6aeb012681c891
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 13:47:02 2009 +0200

    Added company-require-match option.

diff --git a/company.el b/company.el
index 0464697..9da4b47 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-require-match' option.
+;;
 ;; 2009-04-05 (0.2.1)
 ;;    Improved Emacs Lisp back-end behavior for local variables.
 ;;    Added `company-elisp-detect-function-context' option.
@@ -261,6 +263,11 @@ documentation and return it.
 return the cons of buffer and buffer location, or of file and line
 number where the completion candidate was defined.
 
+'require-match: If this value is t, the user is not allowed to enter anything
+not offering as a candidate.  Use with care!  The default value nil gives the
+user that choice with `company-require-match'.  Return value 'never overrides
+that option the other way around.
+
 The back-end should return nil for all commands it does not support or
 does not know about."
   :group 'company
@@ -271,6 +278,16 @@ does not know about."
   :group 'company
   :type '(integer :tag "prefix length"))
 
+(defcustom company-require-match nil
+  "*If enabled, disallow non-matching input.
+This can be a function do determine if a match is required.
+This can be overridden by the back-end, if it returns t or 'never to
+'require-match."
+  :group 'company
+  :type '(choice (const :tag "Off" nil)
+                 (function :tag "Predicate function")
+                 (const :tag "On" t)))
+
 (defcustom company-idle-delay .7
   "*The idle delay in seconds until automatic completions starts.
 A value of nil means never complete automatically, t means complete
@@ -548,6 +565,18 @@ keymap during active completions (`company-active-map'):
   ;; Return non-nil if active.
   company-candidates)
 
+(defsubst company-incremental-p (old-prefix new-prefix)
+  (and (> (length new-prefix) (length old-prefix))
+       (equal old-prefix (substring new-prefix 0 (length old-prefix)))))
+
+(defun company-require-match-p ()
+  (if (functionp company-require-match)
+      (funcall company-require-match)
+    (let ((backend-value (funcall company-backend 'require-match)))
+      (or (eq backend-value t)
+          (and (eq company-require-match t)
+               (not (eq backend-value 'never)))))))
+
 (defun company-continue ()
   (when company-candidates
     (when (funcall company-backend 'no-cache company-prefix)
@@ -562,7 +591,14 @@ keymap during active completions (`company-active-map'):
                            (setq company-prefix new-prefix)
                            (company-update-candidates c)
                            t))))
-        (setq company-candidates nil)))))
+        (if (not (and (company-incremental-p company-prefix new-prefix)
+                      (company-require-match-p)))
+            (setq company-candidates nil)
+          (backward-delete-char (length new-prefix))
+          (insert company-prefix)
+          (ding)
+          (message "Matching input is required")
+          company-candidates)))))
 
 (defun company-begin ()
   (if (or buffer-read-only overriding-terminal-local-map overriding-local-map)

commit 4a66761a7c0cab48e70c0a70449c2dd235616865
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 11:19:45 2009 +0200

    Allow calculating candidates without setting them.

diff --git a/company.el b/company.el
index 245df81..0464697 100644
--- a/company.el
+++ b/company.el
@@ -496,37 +496,32 @@ keymap during active completions (`company-active-map'):
                                          company-selection)))))
     (setq company-selection 0
           company-candidates candidates))
+  ;; Save in cache:
+  (push (cons company-prefix company-candidates) company-candidates-cache)
   ;; Calculate common.
   (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
     (setq company-common (try-completion company-prefix company-candidates)))
   (when (eq company-common t)
     (setq company-candidates nil)))
 
-(defsubst company-calculate-candidates (prefix)
-  (setq company-prefix prefix)
-  (company-update-candidates
-   (or (cdr (assoc prefix company-candidates-cache))
-       (when company-candidates-cache
-         (let ((len (length prefix))
-               (completion-ignore-case (funcall company-backend 'ignore-case))
-               prev)
-           (dotimes (i len)
-             (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
-                                          company-candidates-cache)))
-               (return (all-completions prefix prev))))))
-       (let ((candidates (funcall company-backend 'candidates prefix)))
-         (when company-candidates-predicate
-           (setq candidates
-                 (company-apply-predicate candidates
-                                          company-candidates-predicate)))
-         (unless (funcall company-backend 'sorted)
-           (setq candidates (sort candidates 'string<)))
-         candidates)))
-  (unless company-candidates-cache
-    (company-call-frontends 'show))
-  (unless (assoc prefix company-candidates-cache)
-    (push (cons prefix company-candidates) company-candidates-cache))
-  company-candidates)
+(defun company-calculate-candidates (prefix)
+  (or (cdr (assoc prefix company-candidates-cache))
+      (when company-candidates-cache
+        (let ((len (length prefix))
+              (completion-ignore-case (funcall company-backend 'ignore-case))
+              prev)
+          (dotimes (i len)
+            (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                         company-candidates-cache)))
+              (return (all-completions prefix prev))))))
+      (let ((candidates (funcall company-backend 'candidates prefix)))
+        (when company-candidates-predicate
+          (setq candidates
+                (company-apply-predicate candidates
+                                         company-candidates-predicate)))
+        (unless (funcall company-backend 'sorted)
+          (setq candidates (sort candidates 'string<)))
+        candidates)))
 
 (defun company-idle-begin (buf win tick pos)
   (and company-mode
@@ -562,7 +557,11 @@ keymap during active completions (`company-active-map'):
       (unless (and (= (- (point) (length new-prefix))
                       (- company-point (length company-prefix)))
                    (or (equal company-prefix new-prefix)
-                       (company-calculate-candidates new-prefix)))
+                       (let ((c (company-calculate-candidates new-prefix)))
+                         (when c
+                           (setq company-prefix new-prefix)
+                           (company-update-candidates c)
+                           t))))
         (setq company-candidates nil)))))
 
 (defun company-begin ()
@@ -577,7 +576,9 @@ keymap during active completions (`company-active-map'):
                      (setq prefix (funcall backend 'prefix)))
             (setq company-backend backend)
             (when (company-should-complete prefix)
-              (company-calculate-candidates prefix))
+              (setq company-prefix prefix)
+              (company-update-candidates (company-calculate-candidates prefix))
+              (company-call-frontends 'show))
             (return prefix))))))
   (if company-candidates
       (progn

commit b5f5b6d40dda3b2b4b380819c8363561bab9d14e
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Apr 7 10:15:11 2009 +0200

    Don't let etags search for non-existent file.

diff --git a/company-etags.el b/company-etags.el
index 867dc87..5f2280f 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -39,7 +39,9 @@ buffer automatically."
 (make-variable-buffer-local 'company-etags-buffer-table)
 
 (defun company-etags-find-table ()
-  (let ((dir (file-name-directory buffer-file-name))
+  (let ((dir (if buffer-file-name
+                 (file-name-directory buffer-file-name)
+               (expand-file-name default-directory)))
         file)
     (while (not (or file (equal dir "/")))
       (unless (file-exists-p (setq file (expand-file-name "TAGS" dir)))

commit eb3db8c71692ade0d1b855dac42f9c43ccb4a43b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 5 12:46:20 2009 +0200

    Bumped version to 0.2.1.

diff --git a/company-css.el b/company-css.el
index 4fb8d2e..6d811b7 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 9bd3c22..2a7c1b4 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index c03ebf6..112fd11 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index f7d71dc..867dc87 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index 9a6ad1d..4ae2d07 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index 4f74f18..d3b429a 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index 4042891..0bf68c2 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 32b1a3f..d9d3057 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 901318e..67ab0d3 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index e4179e3..9a9e038 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company 0.2.
+;; This file is part of company 0.2.1.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company.el b/company.el
index 1cd21fa..245df81 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.2
+;; Version: 0.2.1
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-04-05 (0.2.1)
 ;;    Improved Emacs Lisp back-end behavior for local variables.
 ;;    Added `company-elisp-detect-function-context' option.
 ;;    The mouse can now be used for selection.

commit 3bb8c1f192658b2d8cd68e88ca701096f32e9c34
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 5 12:40:22 2009 +0200

    Added elisp improvements to Change Log.

diff --git a/company.el b/company.el
index 131b24e..1cd21fa 100644
--- a/company.el
+++ b/company.el
@@ -65,6 +65,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Improved Emacs Lisp back-end behavior for local variables.
 ;;    Added `company-elisp-detect-function-context' option.
 ;;    The mouse can now be used for selection.
 ;;

commit b7f62a9ee5e2ae511499d4c3ddbaffdb423205bd
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 5 12:39:09 2009 +0200

    Added instructions for mixing back-ends.

diff --git a/company.el b/company.el
index 5e7a667..131b24e 100644
--- a/company.el
+++ b/company.el
@@ -49,6 +49,15 @@
 ;;     ('candidates (list "foobar" "foobaz" "foobarbaz"))
 ;;     ('meta (format "This value is named %s" arg))))
 ;;
+;; Sometimes it is a good idea to mix two back-ends together, for example to
+;; enrich gtags with dabbrev text (to emulate local variables):
+;;
+;; (defun gtags-gtags-dabbrev-backend (command &optional arg &rest ignored)
+;;   (case command
+;;     (prefix (company-gtags 'prefix))
+;;     (candidates (append (company-gtags 'candidates arg)
+;;                         (company-dabbrev 'candidates arg)))))
+;;
 ;; Known Issues:
 ;; When point is at the very end of the buffer, the pseudo-tooltip appears very
 ;; wrong, unless company is allowed to temporarily insert a fake newline.

commit c1ee06620f0af633e6dc51cc5590890c232e6af6
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Apr 5 12:09:58 2009 +0200

    Don't add incomplete text as elisp candidate.

diff --git a/company-elisp.el b/company-elisp.el
index c26e16e..c03ebf6 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -55,7 +55,8 @@ Functions are offered for completion only after ' and \(."
 
 (defun company-elisp-parse-local (prefix vars)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
-                        "\\(?:\\sw\\|\\s_\\)*\\_>\\)")))
+                        "\\(?:\\sw\\|\\s_\\)*\\_>\\)"))
+        (pos (point)))
     (ignore-errors
       (save-excursion
         (dotimes (i company-elisp-parse-depth)
@@ -69,13 +70,17 @@ Functions are offered for completion only after ' and \(."
                   (save-excursion
                     (when (looking-at "[ \t\n]*(")
                       (down-list 1))
-                    (when (looking-at regexp)
-                      (add-to-list 'vars (match-string-no-properties 1))))
+                    (and (looking-at regexp)
+                         ;; Don't add incomplete text as candidate.
+                         (not (eq (match-end 0) pos))
+                         (add-to-list 'vars (match-string-no-properties 1))))
                   (forward-sexp))))
              ((looking-at company-elisp-binding-regexp-1)
               (down-list 2)
-              (when (looking-at regexp)
-                (add-to-list 'vars (match-string-no-properties 1)))))))))
+              (and (looking-at regexp)
+                   ;; Don't add incomplete text as candidate.
+                   (not (eq (match-end 0) pos))
+                   (add-to-list 'vars (match-string-no-properties 1)))))))))
     vars))
 
 (defun company-elisp-candidates (prefix)

commit 40f6fe829bf0648ec03b88f33453a2413b9775f6
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 2 22:20:43 2009 +0200

    Invalidate cache when filtering.

diff --git a/company.el b/company.el
index 99570b9..5e7a667 100644
--- a/company.el
+++ b/company.el
@@ -711,7 +711,9 @@ keymap during active completions (`company-active-map'):
                                candidate))
               `(string-match ,company-search-string candidate))))
   (company-update-candidates
-   (company-apply-predicate company-candidates company-candidates-predicate)))
+   (company-apply-predicate company-candidates company-candidates-predicate))
+  ;; Invalidate cache.
+  (setq company-candidates-cache (cons company-prefix company-candidates)))
 
 (defun company-filter-printing-char ()
   (interactive)

commit 9c146da5331c16ff92ac9436dbb1928bbfacdcb6
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Apr 2 21:44:15 2009 +0200

    Differentiate between dolist/dotimes and regular bindings.

diff --git a/company-elisp.el b/company-elisp.el
index e9ca8fd..c26e16e 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -46,7 +46,12 @@ Functions are offered for completion only after ' and \(."
 (defvar company-elisp-binding-regexp
   (concat "([ \t\n]*\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
                                         "lambda" "lexical-let"))
-          "\\*?"))
+          "\\*?")
+  "Regular expression matching sexps containing variable bindings.")
+
+(defvar company-elisp-binding-regexp-1
+  (concat "([ \t\n]*\\_<" (regexp-opt '("dolist" "dotimes")))
+  "Regular expression matching sexps containing one variable binding.")
 
 (defun company-elisp-parse-local (prefix vars)
   (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
@@ -56,7 +61,8 @@ Functions are offered for completion only after ' and \(."
         (dotimes (i company-elisp-parse-depth)
           (up-list -1)
           (save-excursion
-            (when (looking-at company-elisp-binding-regexp)
+            (cond
+             ((looking-at company-elisp-binding-regexp)
               (down-list 2)
               (ignore-errors
                 (dotimes (i company-elisp-parse-limit)
@@ -65,7 +71,11 @@ Functions are offered for completion only after ' and \(."
                       (down-list 1))
                     (when (looking-at regexp)
                       (add-to-list 'vars (match-string-no-properties 1))))
-                  (forward-sexp))))))))
+                  (forward-sexp))))
+             ((looking-at company-elisp-binding-regexp-1)
+              (down-list 2)
+              (when (looking-at regexp)
+                (add-to-list 'vars (match-string-no-properties 1)))))))))
     vars))
 
 (defun company-elisp-candidates (prefix)

commit c9e084a9fdd46f3c067c40f55ac0d4241d011f4e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 28 19:50:24 2009 +0100

    Don't offer empty string as let-bound variable.

diff --git a/company-elisp.el b/company-elisp.el
index 9c10d13..e9ca8fd 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -49,7 +49,7 @@ Functions are offered for completion only after ' and \(."
           "\\*?"))
 
 (defun company-elisp-parse-local (prefix vars)
-  (let ((regexp (concat "[ \t\n]*\\(" (regexp-quote prefix)
+  (let ((regexp (concat "[ \t\n]*\\(\\_<" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)")))
     (ignore-errors
       (save-excursion

commit f20064a8ac3157403df23c8dd0c202ca1a0e7841
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 28 19:32:47 2009 +0100

    Fixed offering of second argument.

diff --git a/company-elisp.el b/company-elisp.el
index 4f8df83..9c10d13 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -63,9 +63,8 @@ Functions are offered for completion only after ' and \(."
                   (save-excursion
                     (when (looking-at "[ \t\n]*(")
                       (down-list 1))
-                    (if (looking-at regexp)
-                        (add-to-list 'vars (match-string-no-properties 1))
-                      (error)))
+                    (when (looking-at regexp)
+                      (add-to-list 'vars (match-string-no-properties 1))))
                   (forward-sexp))))))))
     vars))
 

commit 8b956d6a100f9a9db2c0bd45c79c28830dcfba7c
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 27 21:23:30 2009 +0100

    Added company-elisp-detect-function-context option.

diff --git a/company-elisp.el b/company-elisp.el
index b77851e..4f8df83 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -20,12 +20,12 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
-(defcustom company-elisp-functions-only-in-context nil
+(defcustom company-elisp-detect-function-context t
   "*If enabled, offer lisp functions only in appropriate contexts.
 Functions are offered for completion only after ' and \(."
   :group 'company
-  :type '(choice (const :tag "off (nil)" nil)
-                 (integer :tag "count" t)))
+  :type '(choice (const :tag "Off" nil)
+                 (const :tag "On" t)))
 
 (defvar company-lisp-symbol-regexp
   "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
@@ -72,7 +72,7 @@ Functions are offered for completion only after ' and \(."
 (defun company-elisp-candidates (prefix)
   (let* ((completion-ignore-case nil)
          (before (char-before (- (point) (length prefix))))
-         (predicate (if (and company-elisp-functions-only-in-context
+         (predicate (if (and company-elisp-detect-function-context
                              (not (eq before ?')))
                         (if (eq before ?\()
                             'fboundp
@@ -91,8 +91,7 @@ Functions are offered for completion only after ' and \(."
          (match-string 0 doc))))
 
 (defun company-elisp (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `emacs-lisp-mode'.
-See `company-elisp-functions-only-in-context'."
+  "A `company-mode' completion back-end for `emacs-lisp-mode'."
   (case command
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
diff --git a/company.el b/company.el
index ea482c7..99570b9 100644
--- a/company.el
+++ b/company.el
@@ -56,7 +56,7 @@
 ;;
 ;;; Change Log:
 ;;
-;;    Added `company-elisp-functions-only-in-context' option.
+;;    Added `company-elisp-detect-function-context' option.
 ;;    The mouse can now be used for selection.
 ;;
 ;; 2009-03-22 (0.2)

commit 526592d7e52c9e4fb3b3418dbccd71c931e524d1
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 27 21:23:30 2009 +0100

    Added company-elisp-functions-only-in-context option.

diff --git a/company-elisp.el b/company-elisp.el
index b312bf2..b77851e 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -20,6 +20,13 @@
 (require 'company)
 (eval-when-compile (require 'cl))
 
+(defcustom company-elisp-functions-only-in-context nil
+  "*If enabled, offer lisp functions only in appropriate contexts.
+Functions are offered for completion only after ' and \(."
+  :group 'company
+  :type '(choice (const :tag "off (nil)" nil)
+                 (integer :tag "count" t)))
+
 (defvar company-lisp-symbol-regexp
   "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
 
@@ -64,7 +71,14 @@
 
 (defun company-elisp-candidates (prefix)
   (let* ((completion-ignore-case nil)
-         (candidates (all-completions prefix obarray 
'company-elisp-predicate)))
+         (before (char-before (- (point) (length prefix))))
+         (predicate (if (and company-elisp-functions-only-in-context
+                             (not (eq before ?')))
+                        (if (eq before ?\()
+                            'fboundp
+                          'boundp)
+                      'company-elisp-predicate))
+         (candidates (all-completions prefix obarray predicate)))
     (company-elisp-parse-local prefix candidates)))
 
 (defun company-elisp-doc (symbol)
@@ -77,7 +91,8 @@
          (match-string 0 doc))))
 
 (defun company-elisp (command &optional arg &rest ignored)
-  "A `company-mode' completion back-end for `emacs-lisp-mode'."
+  "A `company-mode' completion back-end for `emacs-lisp-mode'.
+See `company-elisp-functions-only-in-context'."
   (case command
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
diff --git a/company.el b/company.el
index 12be691..ea482c7 100644
--- a/company.el
+++ b/company.el
@@ -56,6 +56,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-elisp-functions-only-in-context' option.
 ;;    The mouse can now be used for selection.
 ;;
 ;; 2009-03-22 (0.2)

commit 277cd59580de408be7714bc840495699e957e345
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 27 20:37:03 2009 +0100

    Added mouse selection.

diff --git a/company.el b/company.el
index d5ebe5e..12be691 100644
--- a/company.el
+++ b/company.el
@@ -56,6 +56,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    The mouse can now be used for selection.
+;;
 ;; 2009-03-22 (0.2)
 ;;    Added `company-show-location'.
 ;;    Added etags back-end.
@@ -105,6 +107,11 @@
   "*Face used for the selection in the tool tip."
   :group 'company)
 
+(defface company-tooltip-mouse
+  '((default :inherit highlight))
+  "*Face used for the tool tip item under the mouse."
+  :group 'company)
+
 (defface company-tooltip-common
   '((t :inherit company-tooltip
        :foreground "red"))
@@ -282,6 +289,12 @@ The work-around consists of adding a newline.")
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap (kbd "<down>") 'company-select-next)
     (define-key keymap (kbd "<up>") 'company-select-previous)
+    (define-key keymap [down-mouse-1] 'ignore)
+    (define-key keymap [down-mouse-3] 'ignore)
+    (define-key keymap [mouse-1] 'company-complete-mouse)
+    (define-key keymap [mouse-3] 'company-select-mouse)
+    (define-key keymap [up-mouse-1] 'ignore)
+    (define-key keymap [up-mouse-3] 'ignore)
     (define-key keymap "\C-m" 'company-complete-selection)
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
@@ -829,6 +842,21 @@ followed by `company-search-kill-others' after each input."
   (when (company-manual-begin)
     (company-set-selection (1- company-selection))))
 
+(defun company-select-mouse (event)
+  "Select the candidate picked by the mouse."
+  (interactive "e")
+  (when (nth 4 (event-start event))
+    (company-set-selection (- (cdr (posn-col-row (event-start event)))
+                              (cdr (posn-col-row (posn-at-point)))
+                              1))
+    t))
+
+(defun company-complete-mouse (event)
+  "Complete the candidate picked by the mouse."
+  (interactive "e")
+  (when (company-select-mouse event)
+    (company-complete-selection)))
+
 (defun company-complete-selection ()
   "Complete the selected candidate."
   (interactive)
@@ -993,23 +1021,31 @@ when the selection has been changed, the selected 
candidate is completed."
 
 (defun company-fill-propertize (line width selected)
   (setq line (company-safe-substring line 0 width))
-  (add-text-properties 0 width (list 'face 'company-tooltip) line)
+  (add-text-properties 0 width '(face company-tooltip
+                                 mouse-face company-tooltip-mouse)
+                       line)
   (add-text-properties 0 (length company-common)
-                       (list 'face 'company-tooltip-common) line)
+                       '(face company-tooltip-common
+                         mouse-face company-tooltip-mouse)
+                       line)
   (when selected
     (if (and company-search-string
              (string-match (regexp-quote company-search-string) line
                            (length company-prefix)))
         (progn
           (add-text-properties (match-beginning 0) (match-end 0)
-                               '(face company-tooltip-selection) line)
+                               '(face company-tooltip-selection)
+                               line)
           (when (< (match-beginning 0) (length company-common))
             (add-text-properties (match-beginning 0) (length company-common)
                                  '(face company-tooltip-common-selection)
                                  line)))
-      (add-text-properties 0 width '(face company-tooltip-selection) line)
+      (add-text-properties 0 width '(face company-tooltip-selection
+                                          mouse-face company-tooltip-selection)
+                           line)
       (add-text-properties 0 (length company-common)
-                           (list 'face 'company-tooltip-common-selection)
+                           '(face company-tooltip-common-selection
+                             mouse-face company-tooltip-selection)
                            line)))
   line)
 

commit c668a68e40499b291793fcaa280c5b7b09222509
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 27 18:49:34 2009 +0100

    Return nil when etags aren't found.

diff --git a/company-etags.el b/company-etags.el
index eb1e5ec..f7d71dc 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -45,7 +45,8 @@ buffer automatically."
       (unless (file-exists-p (setq file (expand-file-name "TAGS" dir)))
         (setq file nil
               dir (file-name-directory (directory-file-name dir)))))
-    (list file)))
+    (when file
+      (list file))))
 
 (defun company-etags-buffer-table ()
   (or (and company-etags-use-main-table-list tags-table-list)

commit 964c138438e9e94e8095a985d803fa75d0512e34
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 20:12:49 2009 +0100

    Added version number to back-ends.

diff --git a/company-css.el b/company-css.el
index 524c481..4fb8d2e 100644
--- a/company-css.el
+++ b/company-css.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-dabbrev.el b/company-dabbrev.el
index bc6a4dc..9bd3c22 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-elisp.el b/company-elisp.el
index bc22c77..b312bf2 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-etags.el b/company-etags.el
index 84e8e65..eb1e5ec 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-files.el b/company-files.el
index f08479c..9a6ad1d 100644
--- a/company-files.el
+++ b/company-files.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-gtags.el b/company-gtags.el
index f560597..4f74f18 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-ispell.el b/company-ispell.el
index 3d5a7ae..4042891 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-nxml.el b/company-nxml.el
index 6ebcedc..32b1a3f 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-oddmuse.el b/company-oddmuse.el
index 0cdc93c..901318e 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License
diff --git a/company-semantic.el b/company-semantic.el
index a30d97e..e4179e3 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
-;; This file is part of company.
+;; This file is part of company 0.2.
 ;;
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License

commit 22bd25dceb88596c6e337c50ac5d068fa765fb3b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 20:11:07 2009 +0100

    Bumped version to 0.2.

diff --git a/company.el b/company.el
index 9964010..d5ebe5e 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.1.5
+;; Version: 0.2
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -56,6 +56,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-03-22 (0.2)
 ;;    Added `company-show-location'.
 ;;    Added etags back-end.
 ;;    Added work-around for end-of-buffer bug.

commit 9db8d0904c1673f8ae321a30221b06442b3ab159
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 16:58:22 2009 +0100

    Added location referencing.

diff --git a/company-elisp.el b/company-elisp.el
index c40b6f6..bc22c77 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -87,7 +87,11 @@
                    (save-window-excursion
                      (when (or (ignore-errors (describe-function symbol))
                                (ignore-errors (describe-variable symbol)))
-                       (help-buffer)))))))
+                       (help-buffer)))))
+    ('location (let ((sym (intern arg)))
+                 (or (ignore-errors (find-definition-noselect sym nil))
+                     (ignore-errors (find-definition-noselect sym 'defvar))
+                     (ignore-errors (find-definition-noselect sym t)))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company-etags.el b/company-etags.el
index 59aee11..84e8e65 100644
--- a/company-etags.el
+++ b/company-etags.el
@@ -65,6 +65,10 @@ buffer automatically."
                        (completion-ignore-case nil))
                    (and (fboundp 'tags-completion-table)
                         (all-completions arg (tags-completion-table)))))
+    ('location (let ((tags-table-list (company-etags-buffer-table)))
+                 (when (fboundp 'find-tag-noselect)
+                   (let ((buffer (find-tag-noselect arg)))
+                     (cons buffer (with-current-buffer buffer (point)))))))
     ('sorted t)))
 
 (add-to-list 'company-backends 'company-etags)
diff --git a/company-files.el b/company-files.el
index adbdf90..f08479c 100644
--- a/company-files.el
+++ b/company-files.el
@@ -61,6 +61,8 @@
   (case command
     ('prefix (company-files-grab-existing-name))
     ('candidates (company-files-complete arg))
+    ('location (cons (dired-noselect
+                      (file-name-directory (directory-file-name arg))) 1))
     ('sorted t)
     ('no-cache t)))
 
diff --git a/company-gtags.el b/company-gtags.el
index a766767..f560597 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -57,6 +57,17 @@
           (forward-line)))
       (nreverse tags))))
 
+(defun company-gtags-location (tag)
+  (with-temp-buffer
+    (when (= 0 (call-process "global" nil (list (current-buffer) nil)
+                               nil "-x" tag))
+        (goto-char (point-min))
+        (when (looking-at (concat (regexp-quote tag)
+                                  "[ \t]+\\([[:digit:]]+\\)"
+                                  "[ \t]+\\([^ \t]+\\)"))
+          (cons (expand-file-name (match-string 2))
+                (string-to-number (match-string 1)))))))
+
 (defun company-gtags (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for GNU Global."
   (case command
@@ -65,7 +76,8 @@
                   (company-gtags-available)
                (or (company-grab company-gtags-symbol-regexp) "")))
     ('candidates (company-gtags-fetch-tags arg))
-    ('sorted t)))
+    ('sorted t)
+    ('location (company-gtags-location arg))))
 
 (provide 'company-gtags)
 ;;; company-gtags.el ends here
diff --git a/company-semantic.el b/company-semantic.el
index c2f6185..a30d97e 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -74,7 +74,11 @@
                     (semantic-analyze-find-tag arg)))
     ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))
     ;; because "" is an empty context and doesn't return local variables
-    ('no-cache (equal arg ""))))
+    ('no-cache (equal arg ""))
+    ('location (let ((tag (semantic-analyze-find-tag arg)))
+                 (when (buffer-live-p (semantic-tag-buffer tag))
+                   (cons (semantic-tag-buffer tag)
+                         (semantic-tag-start tag)))))))
 
 (provide 'company-semantic)
 ;;; company-semantic.el ends here
diff --git a/company.el b/company.el
index 033a880..9964010 100644
--- a/company.el
+++ b/company.el
@@ -56,6 +56,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-show-location'.
 ;;    Added etags back-end.
 ;;    Added work-around for end-of-buffer bug.
 ;;    Added `company-filter-candidates'.
@@ -79,6 +80,7 @@
 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^No documentation available$")
+(add-to-list 'debug-ignored-errors "^No location available$")
 (add-to-list 'debug-ignored-errors "^Company not enabled$")
 (add-to-list 'debug-ignored-errors "^Company not in search mode$")
 (add-to-list 'debug-ignored-errors "^No candidate number ")
@@ -235,6 +237,10 @@ return a (short) documentation string for it.
 create a buffer (preferably with `company-doc-buffer'), fill it with
 documentation and return it.
 
+'location: The second argument is a completion candidate.  The back-end can
+return the cons of buffer and buffer location, or of file and line
+number where the completion candidate was defined.
+
 The back-end should return nil for all commands it does not support or
 does not know about."
   :group 'company
@@ -278,6 +284,7 @@ The work-around consists of adding a newline.")
     (define-key keymap "\C-m" 'company-complete-selection)
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
+    (define-key keymap "\C-w" 'company-show-location)
     (define-key keymap "\C-s" 'company-search-candidates)
     (define-key keymap "\C-\M-s" 'company-filter-candidates)
     (dotimes (i 10)
@@ -924,6 +931,22 @@ when the selection has been changed, the selected 
candidate is completed."
                           (error "No documentation available")) t))))
 (put 'company-show-doc-buffer 'company-keep t)
 
+(defun company-show-location ()
+  "Temporarily display a buffer showing the selected candidate in context."
+  (interactive)
+  (company-electric
+    (let* ((selected (nth company-selection company-candidates))
+           (location (funcall company-backend 'location selected))
+           (pos (or (cdr location) (error "No location available")))
+           (buffer (or (and (bufferp (car location)) (car location))
+                       (find-file-noselect (car location) t))))
+      (with-selected-window (display-buffer buffer t)
+        (if (bufferp (car location))
+            (goto-char pos)
+          (goto-line pos))
+        (set-window-start nil (point))))))
+(put 'company-show-location 'company-keep t)
+
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-pseudo-tooltip-overlay nil)

commit 5e818d77d453421417acdb292e27010c0053cd2b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 15:35:21 2009 +0100

    Fixed bug causing company to give up after first back-end.

diff --git a/company.el b/company.el
index f12b38b..033a880 100644
--- a/company.el
+++ b/company.el
@@ -540,12 +540,12 @@ keymap during active completions (`company-active-map'):
     (unless company-candidates
       (let (prefix)
         (dolist (backend company-backends)
-          (and (fboundp backend)
-               (setq prefix (funcall backend 'prefix))
-               (company-should-complete prefix)
-               (setq company-backend backend)
-               (company-calculate-candidates prefix))
-          (return prefix)))))
+          (when (and (fboundp backend)
+                     (setq prefix (funcall backend 'prefix)))
+            (setq company-backend backend)
+            (when (company-should-complete prefix)
+              (company-calculate-candidates prefix))
+            (return prefix))))))
   (if company-candidates
       (progn
         (when (and company-end-of-buffer-workaround (eobp))

commit 5cc2c8622a03e0f63715454a58f31be6bda91767
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 14:51:44 2009 +0100

    Extracted company-show-electric-buffer.

diff --git a/company-elisp.el b/company-elisp.el
index b3536eb..c40b6f6 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -84,9 +84,10 @@
     ('candidates (company-elisp-candidates arg))
     ('meta (company-elisp-doc arg))
     ('doc-buffer (let ((symbol (intern arg)))
-                   (when (or (ignore-errors (describe-function symbol))
-                             (ignore-errors (describe-variable symbol)))
-                     (help-buffer))))))
+                   (save-window-excursion
+                     (when (or (ignore-errors (describe-function symbol))
+                               (ignore-errors (describe-variable symbol)))
+                       (help-buffer)))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company.el b/company.el
index 7d482ce..f12b38b 100644
--- a/company.el
+++ b/company.el
@@ -896,28 +896,32 @@ when the selection has been changed, the selected 
candidate is completed."
     (erase-buffer)
     (current-buffer)))
 
+(defmacro company-electric (&rest body)
+  (declare (indent 0) (debug t))
+  `(if company-mode
+       (when (company-manual-begin)
+         (save-window-excursion
+           (let ((height (window-height))
+                 (row (cdr (posn-col-row (posn-at-point)))))
+             ,@body
+             (and (< (window-height) height)
+                  (< (- (window-height) row 2) company-tooltip-limit)
+                  (recenter (- (window-height) row 2)))
+             (while (eq 'scroll-other-window
+                        (key-binding (vector (list (read-event)))))
+               (call-interactively 'scroll-other-window))
+             (when last-input-event
+               (clear-this-command-keys t)
+               (setq unread-command-events (list last-input-event))))))
+     (error "Company not enabled")))
+
 (defun company-show-doc-buffer ()
   "Temporarily show a buffer with the complete documentation for the 
selection."
   (interactive)
-  (unless company-mode (error "Company not enabled"))
-  (when (company-manual-begin)
-    (save-window-excursion
-      (let* ((height (window-height))
-             (row (cdr (posn-col-row (posn-at-point))))
-             (selected (nth company-selection company-candidates))
-             (buffer (funcall company-backend 'doc-buffer selected)))
-        (if (not buffer)
-            (error "No documentation available.")
-          (display-buffer buffer)
-          (and (< (window-height) height)
-               (< (- (window-height) row 2) company-tooltip-limit)
-               (recenter (- (window-height) row 2)))
-          (while (eq 'scroll-other-window
-                     (key-binding (vector (list (read-event)))))
-            (scroll-other-window))
-          (when last-input-event
-            (clear-this-command-keys t)
-            (setq unread-command-events (list last-input-event))))))))
+  (company-electric
+    (let ((selected (nth company-selection company-candidates)))
+      (display-buffer (or (funcall company-backend 'doc-buffer selected)
+                          (error "No documentation available")) t))))
 (put 'company-show-doc-buffer 'company-keep t)
 
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

commit 9b3c085e22dac69f657ddb55c07a172b87c02378
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 13:47:10 2009 +0100

    Use 'company-keep property instead of hard-coded command list.

diff --git a/company.el b/company.el
index 66cbe3f..7d482ce 100644
--- a/company.el
+++ b/company.el
@@ -586,8 +586,11 @@ keymap during active completions (`company-active-map'):
   ;; Don't start again, unless started manually.
   (setq company-point (point)))
 
+(defsubst company-keep (command)
+  (and (symbolp command) (get command 'company-keep)))
+
 (defun company-pre-command ()
-  (unless (eq this-command 'company-show-doc-buffer)
+  (unless (company-keep this-command)
     (condition-case err
         (when company-candidates
           (company-call-frontends 'pre-command))
@@ -599,7 +602,7 @@ keymap during active completions (`company-active-map'):
   (company-uninstall-map))
 
 (defun company-post-command ()
-  (unless (eq this-command 'company-show-doc-buffer)
+  (unless (company-keep this-command)
     (condition-case err
         (progn
           (unless (equal (point) company-point)
@@ -915,6 +918,7 @@ when the selection has been changed, the selected candidate 
is completed."
           (when last-input-event
             (clear-this-command-keys t)
             (setq unread-command-events (list last-input-event))))))))
+(put 'company-show-doc-buffer 'company-keep t)
 
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 4cf6471fbe25d4b5ca07cfb08f2ef230e708790b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 12:26:19 2009 +0100

    Don't let gtags complete in strings or comments.

diff --git a/company-gtags.el b/company-gtags.el
index f5ca914..a766767 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -61,6 +61,7 @@
   "A `company-mode' completion back-end for GNU Global."
   (case command
     ('prefix (and (memq major-mode company-gtags-modes)
+                  (not (company-in-string-or-comment))
                   (company-gtags-available)
                (or (company-grab company-gtags-symbol-regexp) "")))
     ('candidates (company-gtags-fetch-tags arg))

commit 0bfb709cb086d8b4bb68016dbfe194aa4fa1ddfc
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 12:25:04 2009 +0100

    Added etags back-end.

diff --git a/company-etags.el b/company-etags.el
new file mode 100644
index 0000000..59aee11
--- /dev/null
+++ b/company-etags.el
@@ -0,0 +1,75 @@
+;;; company-etags.el --- a company-mode completion back-end for etags
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'etags))
+(eval-when-compile (require 'cl))
+
+(defcustom company-etags-use-main-table-list t
+  "*Always search `tags-table-list' if set.
+If this is disabled, `company-etags' will try to find the one table for each
+buffer automatically."
+  :group 'company-mode
+  :type '(choice (const :tag "off" nil)
+                 (const :tag "on" t)))
+
+(defvar company-etags-symbol-regexp
+  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
+
+(defvar company-etags-modes '(c-mode objc-mode c++-mode java-mode jde-mode
+                              pascal-mode perl-mode python-mode))
+
+(defvar company-etags-buffer-table 'unknown)
+(make-variable-buffer-local 'company-etags-buffer-table)
+
+(defun company-etags-find-table ()
+  (let ((dir (file-name-directory buffer-file-name))
+        file)
+    (while (not (or file (equal dir "/")))
+      (unless (file-exists-p (setq file (expand-file-name "TAGS" dir)))
+        (setq file nil
+              dir (file-name-directory (directory-file-name dir)))))
+    (list file)))
+
+(defun company-etags-buffer-table ()
+  (or (and company-etags-use-main-table-list tags-table-list)
+      (if (eq company-etags-buffer-table 'unknown)
+          (setq company-etags-buffer-table (company-etags-find-table))
+        company-etags-buffer-table)))
+
+(defun company-etags (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for etags."
+  (case command
+    ('prefix (and (memq major-mode company-etags-modes)
+                  (not (company-in-string-or-comment))
+                  (require 'etags nil t)
+                  (company-etags-buffer-table)
+                  (or (company-grab company-etags-symbol-regexp) "")))
+    ('candidates (let ((tags-table-list (company-etags-buffer-table))
+                       (completion-ignore-case nil))
+                   (and (fboundp 'tags-completion-table)
+                        (all-completions arg (tags-completion-table)))))
+    ('sorted t)))
+
+(add-to-list 'company-backends 'company-etags)
+
+(provide 'company-etags)
+;;; company-etags.el ends here
+
+
diff --git a/company.el b/company.el
index 8a0b89a..66cbe3f 100644
--- a/company.el
+++ b/company.el
@@ -56,6 +56,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added etags back-end.
 ;;    Added work-around for end-of-buffer bug.
 ;;    Added `company-filter-candidates'.
 ;;    More local Lisp variables are now included in the candidates.
@@ -204,8 +205,8 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-gtags company-oddmuse
-                              company-files company-dabbrev)
+                              company-semantic company-gtags company-etags
+                              company-oddmuse company-files company-dabbrev)
   "*The list of active back-ends (completion engines).
 Each back-end is a function that takes a variable number of arguments.
 The first argument is the command requested from the back-end.  It is one

commit af101df958f47c999cc3a27e4d056d6ef0aed04a
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 10:46:53 2009 +0100

    Restore buffer modified state when using work-around.

diff --git a/company.el b/company.el
index a311434..8a0b89a 100644
--- a/company.el
+++ b/company.el
@@ -547,10 +547,9 @@ keymap during active completions (`company-active-map'):
           (return prefix)))))
   (if company-candidates
       (progn
-        (and company-end-of-buffer-workaround
-             (eobp)
-             (setq company-added-newline t)
-             (save-excursion (insert "\n")))
+        (when (and company-end-of-buffer-workaround (eobp))
+          (save-excursion (insert "\n"))
+          (setq company-added-newline (buffer-chars-modified-tick)))
         (setq company-point (point))
         (company-enable-overriding-keymap company-active-map)
         (company-call-frontends 'update))
@@ -559,7 +558,11 @@ keymap during active completions (`company-active-map'):
 (defun company-cancel ()
   (and company-added-newline
        (> (point-max) (point-min))
-       (delete-region (1- (point-max)) (point-max)))
+       (let ((tick (buffer-chars-modified-tick)))
+         (delete-region (1- (point-max)) (point-max))
+         (equal tick company-added-newline))
+       ;; Only set unmodified when tick remained the same since insert.
+       (set-buffer-modified-p nil))
   (setq company-added-newline nil
         company-backend nil
         company-prefix nil

commit 78be74cdcd313eb307718535e54ba79962a91155
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 10:29:28 2009 +0100

    Added work-around for end-of-buffer bug.

diff --git a/company.el b/company.el
index 4dd4c28..a311434 100644
--- a/company.el
+++ b/company.el
@@ -51,10 +51,12 @@
 ;;
 ;; Known Issues:
 ;; When point is at the very end of the buffer, the pseudo-tooltip appears very
-;; wrong.
+;; wrong, unless company is allowed to temporarily insert a fake newline.
+;; This behavior is enabled by `company-end-of-buffer-workaround'.
 ;;
 ;;; Change Log:
 ;;
+;;    Added work-around for end-of-buffer bug.
 ;;    Added `company-filter-candidates'.
 ;;    More local Lisp variables are now included in the candidates.
 ;;
@@ -257,6 +259,10 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
   :type '(choice (const :tag "off" nil)
                  (const :tag "on" t)))
 
+(defvar company-end-of-buffer-workaround t
+  "*Work around a visualization bug when completing at the end of the buffer.
+The work-around consists of adding a newline.")
+
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-mode-map (make-sparse-keymap)
@@ -404,6 +410,9 @@ keymap during active completions (`company-active-map'):
 
 (defvar company-timer nil)
 
+(defvar company-added-newline nil)
+(make-variable-buffer-local 'company-added-newline)
+
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
@@ -538,13 +547,21 @@ keymap during active completions (`company-active-map'):
           (return prefix)))))
   (if company-candidates
       (progn
+        (and company-end-of-buffer-workaround
+             (eobp)
+             (setq company-added-newline t)
+             (save-excursion (insert "\n")))
         (setq company-point (point))
         (company-enable-overriding-keymap company-active-map)
         (company-call-frontends 'update))
     (company-cancel)))
 
 (defun company-cancel ()
-  (setq company-backend nil
+  (and company-added-newline
+       (> (point-max) (point-min))
+       (delete-region (1- (point-max)) (point-max)))
+  (setq company-added-newline nil
+        company-backend nil
         company-prefix nil
         company-candidates nil
         company-candidates-length nil

commit 37a7281b1e787264b80b9af03fd0fe47d50f93eb
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 10:34:38 2009 +0100

    Added missing 'show call.

diff --git a/company.el b/company.el
index 443fbc2..4dd4c28 100644
--- a/company.el
+++ b/company.el
@@ -479,6 +479,8 @@ keymap during active completions (`company-active-map'):
          (unless (funcall company-backend 'sorted)
            (setq candidates (sort candidates 'string<)))
          candidates)))
+  (unless company-candidates-cache
+    (company-call-frontends 'show))
   (unless (assoc prefix company-candidates-cache)
     (push (cons prefix company-candidates) company-candidates-cache))
   company-candidates)

commit 6e5f510fba140a1e4712fdb032dc05f73dfc790a
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 10:20:44 2009 +0100

    Note that search commands work all the time.

diff --git a/company.el b/company.el
index 30473b6..443fbc2 100644
--- a/company.el
+++ b/company.el
@@ -292,7 +292,8 @@ Completion can be controlled with the commands:
 called before `company-idle-delay', completion will also start.
 
 Completions can be searched with `company-search-candidates' or
-`company-filter-candidates'.
+`company-filter-candidates'.  These can be used while completion is
+inactive, as well.
 
 The completion data is retrieved using `company-backends' and displayed using
 `company-frontends'.

commit f68775a16aaa8f9bf6240e0567aab3094dafb850
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 10:13:34 2009 +0100

    Highlight search in preview overlay.

diff --git a/company.el b/company.el
index 6b57629..30473b6 100644
--- a/company.el
+++ b/company.el
@@ -128,6 +128,12 @@
   "*Face used for the common part of the completion preview."
   :group 'company)
 
+(defface company-preview-search
+  '((t :inherit company-preview
+       :background "blue1"))
+  "*Face used for the search string in the completion preview."
+  :group 'company)
+
 (defface company-echo nil
   "*Face used for completions in the echo area."
   :group 'company)
@@ -158,7 +164,7 @@
   (set variable value))
 
 (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
-                               company-preview-if-just-one-frontend
+                               company-preview-frontend
                                company-echo-metadata-frontend)
   "*The list of active front-ends (visualizations).
 Each front-end is a function that takes one argument.  It is called with
@@ -1145,16 +1151,25 @@ when the selection has been changed, the selected 
candidate is completed."
 
   (setq company-preview-overlay (make-overlay pos pos))
 
-  (let ((completion (company-strip-prefix (nth company-selection
-                                               company-candidates))))
+  (let ((completion(nth company-selection company-candidates)))
+    (setq completion (propertize completion 'face 'company-preview))
+    (add-text-properties 0 (length company-common)
+                         '(face company-preview-common) completion)
+
+    ;; Add search string
+    (and company-search-string
+         (string-match (regexp-quote company-search-string) completion)
+         (add-text-properties (match-beginning 0)
+                              (match-end 0)
+                              '(face company-preview-search)
+                              completion))
+
+    (setq completion (company-strip-prefix completion))
+
     (and (equal pos (point))
          (not (equal completion ""))
          (add-text-properties 0 1 '(cursor t) completion))
 
-    (setq completion (propertize completion 'face 'company-preview))
-    (add-text-properties 0 (- (length company-common) (length company-prefix))
-                         '(face company-preview-common) completion)
-
     (overlay-put company-preview-overlay 'after-string completion)
     (overlay-put company-preview-overlay 'window (selected-window))))
 

commit 2e4187d8d935a7b4623f398dbd247379395743aa
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 08:26:08 2009 +0100

    Added keymap names to mode documentation.

diff --git a/company.el b/company.el
index f74b09e..6b57629 100644
--- a/company.el
+++ b/company.el
@@ -291,10 +291,10 @@ Completions can be searched with 
`company-search-candidates' or
 The completion data is retrieved using `company-backends' and displayed using
 `company-frontends'.
 
-regular keymap:
+regular keymap (`company-mode-map'):
 
 \\{company-mode-map}
-keymap during active completions:
+keymap during active completions (`company-active-map'):
 
 \\{company-active-map}"
   nil " comp" company-mode-map

commit e169cf3c9d1ea1a516d58a875fae2ee93bbc4c36
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 08:24:40 2009 +0100

    Fixed wrong command in Emacs 22 search map.

diff --git a/company.el b/company.el
index 11e2080..f74b09e 100644
--- a/company.el
+++ b/company.el
@@ -703,7 +703,7 @@ keymap during active completions:
         (let ((l (generic-character-list))
               (table (nth 1 keymap)))
           (while l
-            (set-char-table-default table (car l) 'isearch-printing-char)
+            (set-char-table-default table (car l) 
'company-search-printing-char)
             (setq l (cdr l))))))
     (define-key keymap [t] 'company-search-other-char)
     (while (< i ?\s)

commit eed205aff7f94fc578dc48d40ac80aa43794ba34
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 08:24:04 2009 +0100

    Removed full doc from company-search-mode.

diff --git a/company.el b/company.el
index 2a96b39..11e2080 100644
--- a/company.el
+++ b/company.el
@@ -727,17 +727,9 @@ keymap during active completions:
   "Keymap used for incrementally searching the completion candidates.")
 
 (define-minor-mode company-search-mode
-  "Start searching the completion candidates incrementally.
-
-\\<company-search-map>Search can be controlled with the commands:
-- `company-search-repeat-forward' (\\[company-search-repeat-forward])
-- `company-search-repeat-backward' (\\[company-search-repeat-backward])
-- `company-search-abort' (\\[company-search-abort])
-
-Regular characters are appended to the search string.
-
-The command `company-search-kill-others' (\\[company-search-kill-others]) uses
- the search string to limit the completion candidates."
+  "Search mode for completion candidates.
+Don't start this directly, use `company-search-candidates' or
+`company-filter-candidates'."
   nil company-search-lighter nil
   (if company-search-mode
       (if (company-manual-begin)

commit ab9c34521252bb3d81fa77868eb3ea7923eea45e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 22 08:22:08 2009 +0100

    Added company-filter-candidates.

diff --git a/company.el b/company.el
index d93a663..2a96b39 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-filter-candidates'.
 ;;    More local Lisp variables are now included in the candidates.
 ;;
 ;; 2009-03-21 (0.1.5)
@@ -265,6 +266,7 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     (define-key keymap "\C-s" 'company-search-candidates)
+    (define-key keymap "\C-\M-s" 'company-filter-candidates)
     (dotimes (i 10)
       (define-key keymap (vector (+ (aref (kbd "M-0") 0) i))
         `(lambda () (interactive) (company-complete-number ,i))))
@@ -283,7 +285,8 @@ Completion can be controlled with the commands:
 `company-select-next', `company-select-previous'.  If these commands are
 called before `company-idle-delay', completion will also start.
 
-Completions can be searched with `company-search-candidates'.
+Completions can be searched with `company-search-candidates' or
+`company-filter-candidates'.
 
 The completion data is retrieved using `company-backends' and displayed using
 `company-frontends'.
@@ -644,24 +647,33 @@ keymap during active completions:
         (ding)
       (company-set-selection (- company-selection pos 1) t))))
 
-(defsubst company-create-match-predicate (search-string)
-  `(lambda (candidate)
-     ,(if company-candidates-predicate
-          `(and (string-match ,search-string candidate)
-                (funcall ,company-candidates-predicate candidate))
-        `(string-match ,company-search-string candidate))))
+(defun company-create-match-predicate ()
+  (setq company-candidates-predicate
+        `(lambda (candidate)
+           ,(if company-candidates-predicate
+                `(and (string-match ,company-search-string candidate)
+                      (funcall ,company-candidates-predicate
+                               candidate))
+              `(string-match ,company-search-string candidate))))
+  (company-update-candidates
+   (company-apply-predicate company-candidates company-candidates-predicate)))
+
+(defun company-filter-printing-char ()
+  (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
+  (company-search-printing-char)
+  (company-create-match-predicate)
+  (company-call-frontends 'update))
 
 (defun company-search-kill-others ()
   "Limit the completion candidates to the ones matching the search string."
   (interactive)
   (unless company-mode (error "Company not enabled"))
   (unless company-search-mode (error "Company not in search mode"))
-  (let ((predicate (company-create-match-predicate company-search-string)))
-    (setq company-candidates-predicate predicate)
-    (company-update-candidates (company-apply-predicate company-candidates
-                                                        predicate))
-    (company-search-mode 0)
-    (company-call-frontends 'update)))
+  (company-create-match-predicate)
+  (company-search-mode 0)
+  (company-call-frontends 'update))
 
 (defun company-search-abort ()
   "Abort searching the completion candidates."
@@ -731,7 +743,6 @@ The command `company-search-kill-others' 
(\\[company-search-kill-others]) uses
       (if (company-manual-begin)
           (progn
             (setq company-search-old-selection company-selection)
-            (company-enable-overriding-keymap company-search-map)
             (company-call-frontends 'update))
         (setq company-search-mode nil))
     (kill-local-variable 'company-search-string)
@@ -752,7 +763,24 @@ Regular characters are appended to the search string.
 The command `company-search-kill-others' (\\[company-search-kill-others]) uses
  the search string to limit the completion candidates."
   (interactive)
-  (company-search-mode 1))
+  (company-search-mode 1)
+  (company-enable-overriding-keymap company-search-map))
+
+(defvar company-filter-map
+  (let ((keymap (make-keymap)))
+    (define-key keymap [remap company-search-printing-char]
+      'company-filter-printing-char)
+    (set-keymap-parent keymap company-search-map)
+    keymap)
+  "Keymap used for incrementally searching the completion candidates.")
+
+(defun company-filter-candidates ()
+  "Start filtering the completion candidates incrementally.
+This works the same way as `company-search-candidates' immediately
+followed by `company-search-kill-others' after each input."
+  (interactive)
+  (company-search-mode 1)
+  (company-enable-overriding-keymap company-filter-map))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 6cb973ff77b4d0eb1b27f5217b2eac6d317ce2c0
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 22:55:50 2009 +0100

    Offer more Lisp variables as candidates.

diff --git a/company-elisp.el b/company-elisp.el
index 341eca8..b3536eb 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -36,7 +36,12 @@
 (defvar company-elisp-parse-limit 30)
 (defvar company-elisp-parse-depth 100)
 
-(defun company-elisp-parse-let (prefix vars)
+(defvar company-elisp-binding-regexp
+  (concat "([ \t\n]*\\_<" (regexp-opt '("let" "defun" "defmacro" "defsubst"
+                                        "lambda" "lexical-let"))
+          "\\*?"))
+
+(defun company-elisp-parse-local (prefix vars)
   (let ((regexp (concat "[ \t\n]*\\(" (regexp-quote prefix)
                         "\\(?:\\sw\\|\\s_\\)*\\_>\\)")))
     (ignore-errors
@@ -44,7 +49,7 @@
         (dotimes (i company-elisp-parse-depth)
           (up-list -1)
           (save-excursion
-            (when (looking-at "([ \t\n]*let")
+            (when (looking-at company-elisp-binding-regexp)
               (down-list 2)
               (ignore-errors
                 (dotimes (i company-elisp-parse-limit)
@@ -60,7 +65,7 @@
 (defun company-elisp-candidates (prefix)
   (let* ((completion-ignore-case nil)
          (candidates (all-completions prefix obarray 
'company-elisp-predicate)))
-    (company-elisp-parse-let prefix candidates)))
+    (company-elisp-parse-local prefix candidates)))
 
 (defun company-elisp-doc (symbol)
   (let* ((symbol (intern symbol))
diff --git a/company.el b/company.el
index 9c62ed1..d93a663 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    More local Lisp variables are now included in the candidates.
+;;
 ;; 2009-03-21 (0.1.5)
 ;;    Fixed elisp documentation buffer always showing the same doc.
 ;;    Added `company-echo-strip-common-frontend'.

commit 98ba72c1b8a0f05d954ffd7773d6a11f0a980fe9
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 22:44:36 2009 +0100

    Fixed duplicate completions for let-bound variables.

diff --git a/company-elisp.el b/company-elisp.el
index fdcb970..341eca8 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -36,8 +36,9 @@
 (defvar company-elisp-parse-limit 30)
 (defvar company-elisp-parse-depth 100)
 
-(defun company-elisp-parse-let ()
-  (let (vars)
+(defun company-elisp-parse-let (prefix vars)
+  (let ((regexp (concat "[ \t\n]*\\(" (regexp-quote prefix)
+                        "\\(?:\\sw\\|\\s_\\)*\\_>\\)")))
     (ignore-errors
       (save-excursion
         (dotimes (i company-elisp-parse-depth)
@@ -50,12 +51,17 @@
                   (save-excursion
                     (when (looking-at "[ \t\n]*(")
                       (down-list 1))
-                    (if (looking-at "[ \t\n]*\\(\\(?:\\sw\\|\\s_\\)+\\)")
+                    (if (looking-at regexp)
                         (add-to-list 'vars (match-string-no-properties 1))
                       (error)))
                   (forward-sexp))))))))
     vars))
 
+(defun company-elisp-candidates (prefix)
+  (let* ((completion-ignore-case nil)
+         (candidates (all-completions prefix obarray 
'company-elisp-predicate)))
+    (company-elisp-parse-let prefix candidates)))
+
 (defun company-elisp-doc (symbol)
   (let* ((symbol (intern symbol))
          (doc (if (fboundp symbol)
@@ -70,10 +76,7 @@
   (case command
     ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
-    ('candidates (let ((completion-ignore-case nil))
-                   (append (all-completions arg (company-elisp-parse-let))
-                           (all-completions arg obarray
-                                            'company-elisp-predicate))))
+    ('candidates (company-elisp-candidates arg))
     ('meta (company-elisp-doc arg))
     ('doc-buffer (let ((symbol (intern arg)))
                    (when (or (ignore-errors (describe-function symbol))

commit 7a27317ba48f4e447e5ab76fd793d6ba589a46e3
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 12:21:18 2009 +0100

    Bumped version to 0.1.5.

diff --git a/company.el b/company.el
index c4ee791..9c62ed1 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 0.1
+;; Version: 0.1.5
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-03-21 (0.1.5)
 ;;    Fixed elisp documentation buffer always showing the same doc.
 ;;    Added `company-echo-strip-common-frontend'.
 ;;    Added `company-show-numbers' option and M-0 ... M-9 default bindings.

commit 6b999cae54d183fa744403463c39ffbe6291cc95
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 12:36:05 2009 +0100

    Fixed elisp documentation buffer always showing the same doc.

diff --git a/company-elisp.el b/company-elisp.el
index 7fcea0c..fdcb970 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -75,8 +75,10 @@
                            (all-completions arg obarray
                                             'company-elisp-predicate))))
     ('meta (company-elisp-doc arg))
-    ('doc-buffer (describe-function 'describe-function)
-                 (help-buffer))))
+    ('doc-buffer (let ((symbol (intern arg)))
+                   (when (or (ignore-errors (describe-function symbol))
+                             (ignore-errors (describe-variable symbol)))
+                     (help-buffer))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company.el b/company.el
index 9e61280..c4ee791 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Fixed elisp documentation buffer always showing the same doc.
 ;;    Added `company-echo-strip-common-frontend'.
 ;;    Added `company-show-numbers' option and M-0 ... M-9 default bindings.
 ;;    Don't hide the echo message if it isn't shown.

commit 5bd93ef0725814e30ae15ce94a1e65c6c3abc0d2
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 10:04:48 2009 +0100

    Added note that commands will start completion manually.

diff --git a/company.el b/company.el
index 075a0f0..9e61280 100644
--- a/company.el
+++ b/company.el
@@ -276,7 +276,8 @@ Completion starts automatically, depending on the values
 
 Completion can be controlled with the commands:
 `company-complete-common', `company-complete-selection', `company-complete',
-`company-select-next', `company-select-previous'.
+`company-select-next', `company-select-previous'.  If these commands are
+called before `company-idle-delay', completion will also start.
 
 Completions can be searched with `company-search-candidates'.
 

commit 33cf28d7fb8c3f83521329a4927e4985dd3593d9
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 10:03:22 2009 +0100

    Added missing period in documentation.

diff --git a/company.el b/company.el
index a9cda04..075a0f0 100644
--- a/company.el
+++ b/company.el
@@ -272,7 +272,7 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
 (define-minor-mode company-mode
   "\"complete anything\"; in in-buffer completion framework.
 Completion starts automatically, depending on the values
-`company-idle-delay' and `company-minimum-prefix-length'
+`company-idle-delay' and `company-minimum-prefix-length'.
 
 Completion can be controlled with the commands:
 `company-complete-common', `company-complete-selection', `company-complete',

commit 17940330a40a3a4a1a62cb90758291f96b1ef71c
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 09:58:05 2009 +0100

    Made company-manual-begin a command.

diff --git a/company.el b/company.el
index 9e6ef7a..a9cda04 100644
--- a/company.el
+++ b/company.el
@@ -483,6 +483,7 @@ keymap during active completions:
            (company-post-command)))))
 
 (defun company-manual-begin ()
+  (interactive)
   (unless company-mode (error "Company not enabled"))
   (and company-mode
        (not company-candidates)

commit 820b860b33c7976ec6ac718b5c4bfae473cdd50b
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 09:44:30 2009 +0100

    Added missing custom entry for company-echo-metadata-frontend.

diff --git a/company.el b/company.el
index 0ee5e79..9e6ef7a 100644
--- a/company.el
+++ b/company.el
@@ -179,6 +179,8 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
   :type '(repeat (choice (const :tag "echo" company-echo-frontend)
                          (const :tag "echo, strip common"
                                 company-echo-strip-common-frontend)
+                         (const :tag "show echo meta-data in echo"
+                                company-echo-metadata-frontend)
                          (const :tag "pseudo tooltip"
                                 company-pseudo-tooltip-frontend)
                          (const :tag "pseudo tooltip, multiple only"

commit 18310742c22c57570cfcb11401b67e67849c2bee
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 09:36:24 2009 +0100

    Added company-echo-strip-common-frontend.

diff --git a/company.el b/company.el
index b1610bf..0ee5e79 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-echo-strip-common-frontend'.
 ;;    Added `company-show-numbers' option and M-0 ... M-9 default bindings.
 ;;    Don't hide the echo message if it isn't shown.
 ;;
@@ -176,6 +177,8 @@ The visualized data is stored in `company-prefix', 
`company-candidates',
   :set 'company-frontends-set
   :group 'company
   :type '(repeat (choice (const :tag "echo" company-echo-frontend)
+                         (const :tag "echo, strip common"
+                                company-echo-strip-common-frontend)
                          (const :tag "pseudo tooltip"
                                 company-pseudo-tooltip-frontend)
                          (const :tag "pseudo tooltip, multiple only"
@@ -1198,6 +1201,31 @@ when the selection has been changed, the selected 
candidate is completed."
 
     (mapconcat 'identity (nreverse msg) " ")))
 
+(defun company-echo-strip-common-format ()
+
+  (let ((limit (window-width (minibuffer-window)))
+        (len (+ (length company-prefix) 2))
+        ;; Roll to selection.
+        (candidates (nthcdr company-selection company-candidates))
+        (i (if company-show-numbers company-selection 99999))
+        msg comp)
+
+    (while candidates
+      (setq comp (company-strip-prefix (pop candidates))
+            len (+ len 2 (length comp)))
+      (when (< i 10)
+        ;; Add number.
+        (setq comp (format "%s (%d)" comp i))
+        (incf len 4)
+        (incf i))
+      (if (>= len limit)
+          (setq candidates nil)
+        (push (propertize comp 'face 'company-echo) msg)))
+
+    (concat (propertize company-prefix 'face 'company-echo-common) "{"
+            (mapconcat 'identity (nreverse msg) ", ")
+            "}")))
+
 (defun company-echo-hide ()
   (when company-echo-timer
     (cancel-timer company-echo-timer))
@@ -1212,6 +1240,13 @@ when the selection has been changed, the selected 
candidate is completed."
     ('post-command (company-echo-show-soon 'company-echo-format))
     ('hide (company-echo-hide))))
 
+(defun company-echo-strip-common-frontend (command)
+  "A `company-mode' front-end showing the candidates in the echo area."
+  (case command
+    ('pre-command (company-echo-show-soon))
+    ('post-command (company-echo-show-soon 'company-echo-strip-common-format))
+    ('hide (company-echo-hide))))
+
 (defun company-echo-metadata-frontend (command)
   "A `company-mode' front-end showing the documentation in the echo area."
   (case command

commit bf03f1b7aead0cf2598cc42dd74120e58d3e3c12
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 09:33:16 2009 +0100

    Added company-show-numbers option and M-0 ... M-9 default bindings.

diff --git a/company.el b/company.el
index 92e1861..b1610bf 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Added `company-show-numbers' option and M-0 ... M-9 default bindings.
 ;;    Don't hide the echo message if it isn't shown.
 ;;
 ;; 2009-03-20 (0.1)

commit 82161ce9865200f03e942e88f5e806df29bfab1e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 21 09:21:12 2009 +0100

    Added option for quickly selection completions by numbers.

diff --git a/company.el b/company.el
index da3a280..92e1861 100644
--- a/company.el
+++ b/company.el
@@ -71,6 +71,7 @@
 (add-to-list 'debug-ignored-errors "^No documentation available$")
 (add-to-list 'debug-ignored-errors "^Company not enabled$")
 (add-to-list 'debug-ignored-errors "^Company not in search mode$")
+(add-to-list 'debug-ignored-errors "^No candidate number ")
 
 (defgroup company nil
   "Extensible inline text completion mechanism"
@@ -233,6 +234,12 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
                  (const :tag "immediate (t)" t)
                  (number :tag "seconds")))
 
+(defcustom company-show-numbers nil
+  "*If enabled, show quick-access numbers for the first ten candidates."
+  :group 'company
+  :type '(choice (const :tag "off" nil)
+                 (const :tag "on" t)))
+
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-mode-map (make-sparse-keymap)
@@ -248,6 +255,10 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     (define-key keymap "\C-s" 'company-search-candidates)
+    (dotimes (i 10)
+      (define-key keymap (vector (+ (aref (kbd "M-0") 0) i))
+        `(lambda () (interactive) (company-complete-number ,i))))
+
     keymap)
   "Keymap that is enabled during an active completion.")
 
@@ -770,6 +781,15 @@ when the selection has been changed, the selected 
candidate is completed."
       (call-interactively 'company-complete-common)
       (setq this-command 'company-complete-common))))
 
+(defun company-complete-number (n)
+  "Complete the Nth candidate."
+  (when (company-manual-begin)
+    (and (< n 1) (> n company-candidates-length)
+         (error "No candidate number %d" n))
+    (decf n)
+    (insert (company-strip-prefix (nth n company-candidates)))
+    (company-abort)))
+
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defconst company-space-strings-limit 100)
@@ -933,6 +953,7 @@ when the selection has been changed, the selected candidate 
is completed."
 (defun company-create-lines (column selection limit)
 
   (let ((len company-candidates-length)
+        (numbered 99999)
         lines
         width
         lines-copy
@@ -960,14 +981,28 @@ when the selection has been changed, the selected 
candidate is completed."
       (setq width (max (length (pop lines-copy)) width)))
     (setq width (min width (- (window-width) column)))
 
+    (setq lines-copy lines)
+
+    ;; number can make tooltip too long
+    (and company-show-numbers
+         (< (setq numbered company-tooltip-offset) 10)
+         (incf width 2))
+
     (when previous
       (push (propertize (company-safe-substring previous 0 width)
                         'face 'company-tooltip)
             new))
 
     (dotimes (i len)
-      (push (company-fill-propertize (company-reformat (pop lines))
-                                     width (equal i selection))
+      (push (company-fill-propertize
+             (if (>= numbered 10)
+                 (company-reformat (pop lines))
+               (incf numbered)
+               (format "%s %d"
+                       (company-safe-substring (company-reformat (pop lines))
+                                               0 (- width 2))
+                       (mod numbered 10)))
+             width (equal i selection))
             new))
 
     (when remainder
@@ -1138,16 +1173,26 @@ when the selection has been changed, the selected 
candidate is completed."
         (len -1)
         ;; Roll to selection.
         (candidates (nthcdr company-selection company-candidates))
+        (i (if company-show-numbers company-selection 99999))
         comp msg)
 
     (while candidates
       (setq comp (company-reformat (pop candidates))
             len (+ len 1 (length comp)))
-      (if (>= len limit)
-          (setq candidates nil)
+      (if (< i 10)
+          ;; Add number.
+          (progn
+            (setq comp (propertize (format "%d: %s" i comp)
+                                   'face 'company-echo))
+            (incf len 3)
+            (incf i)
+            (add-text-properties 3 (+ 3 (length company-common))
+                                 '(face company-echo-common) comp))
         (setq comp (propertize comp 'face 'company-echo))
         (add-text-properties 0 (length company-common)
-                             '(face company-echo-common) comp)
+                             '(face company-echo-common) comp))
+      (if (>= len limit)
+          (setq candidates nil)
         (push comp msg)))
 
     (mapconcat 'identity (nreverse msg) " ")))

commit a1824516fbd28c98b873ec947bfcd152a68909b7
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 17:55:00 2009 +0100

    Check back-ends when mode is started.

diff --git a/company.el b/company.el
index 6ff460a..da3a280 100644
--- a/company.el
+++ b/company.el
@@ -276,7 +276,13 @@ keymap during active completions:
   (if company-mode
       (progn
         (add-hook 'pre-command-hook 'company-pre-command nil t)
-        (add-hook 'post-command-hook 'company-post-command nil t))
+        (add-hook 'post-command-hook 'company-post-command nil t)
+        (dolist (backend company-backends)
+          (unless (fboundp backend)
+            (ignore-errors (require backend nil t)))
+          (unless (fboundp backend)
+            (message "Company back-end '%s' could not be initialized"
+                     backend))))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
     (company-cancel)
@@ -366,8 +372,6 @@ keymap during active completions:
 
 (defvar company-timer nil)
 
-(defvar company-disabled-backends nil)
-
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
@@ -491,18 +495,12 @@ keymap during active completions:
     (unless company-candidates
       (let (prefix)
         (dolist (backend company-backends)
-          (unless (fboundp backend)
-            (ignore-errors (require backend nil t)))
-          (if (fboundp backend)
-              (when (setq prefix (funcall backend 'prefix))
-                (when (company-should-complete prefix)
-                  (setq company-backend backend)
-                  (company-calculate-candidates prefix))
-                (return prefix))
-            (unless (memq backend company-disabled-backends)
-              (push backend company-disabled-backends)
-              (message "Company back-end '%s' could not be initialized"
-                       backend)))))))
+          (and (fboundp backend)
+               (setq prefix (funcall backend 'prefix))
+               (company-should-complete prefix)
+               (setq company-backend backend)
+               (company-calculate-candidates prefix))
+          (return prefix)))))
   (if company-candidates
       (progn
         (setq company-point (point))

commit 29b06b9b4fd572d2ff4a3ce678d13ec0e19a4ab5
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 16:36:33 2009 +0100

    Don't hide the echo message if it isn't shown.
    
    Previously this blocked all other echo messages.

diff --git a/company.el b/company.el
index 7022338..6ff460a 100644
--- a/company.el
+++ b/company.el
@@ -55,6 +55,8 @@
 ;;
 ;;; Change Log:
 ;;
+;;    Don't hide the echo message if it isn't shown.
+;;
 ;; 2009-03-20 (0.1)
 ;;    Initial release.
 ;;
@@ -1155,8 +1157,9 @@ when the selection has been changed, the selected 
candidate is completed."
 (defun company-echo-hide ()
   (when company-echo-timer
     (cancel-timer company-echo-timer))
-  (setq company-echo-last-msg "")
-  (company-echo-show))
+  (unless (equal company-echo-last-msg "")
+    (setq company-echo-last-msg "")
+    (company-echo-show)))
 
 (defun company-echo-frontend (command)
   "A `company-mode' front-end showing the candidates in the echo area."

commit cd899b81aa4160cc6045e3e3dc1050ee5b648e37
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 22:37:56 2009 +0100

    Bumped version to 0.1.

diff --git a/company.el b/company.el
index 1967c05..7022338 100644
--- a/company.el
+++ b/company.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2009 Nikolaj Schumacher
 ;;
 ;; Author: Nikolaj Schumacher <bugs * nschum de>
-;; Version: 
+;; Version: 0.1
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
 ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
@@ -55,6 +55,7 @@
 ;;
 ;;; Change Log:
 ;;
+;; 2009-03-20 (0.1)
 ;;    Initial release.
 ;;
 ;;; Code:

commit c1d7dcba0072e53c6feda05d633bdf03f52c8d4e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 22:37:03 2009 +0100

    Added compatibility info for Emacs 22.

diff --git a/company.el b/company.el
index 662e51d..1967c05 100644
--- a/company.el
+++ b/company.el
@@ -6,7 +6,7 @@
 ;; Version: 
 ;; Keywords: abbrev, convenience, matchis
 ;; URL: http://nschum.de/src/emacs/company/
-;; Compatibility: GNU Emacs 23.x
+;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x
 ;;
 ;; This file is NOT part of GNU Emacs.
 ;;

commit acc33ff6db2942e6d9c3a2533391fe5e7402f788
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 13:06:49 2009 +0100

    Make sure pseudo-tooltip is shown when switching the window.

diff --git a/company.el b/company.el
index bfe9dcd..662e51d 100644
--- a/company.el
+++ b/company.el
@@ -1039,7 +1039,8 @@ when the selection has been changed, the selected 
candidate is completed."
   (when company-pseudo-tooltip-overlay
     (overlay-put company-pseudo-tooltip-overlay 'invisible t)
     (overlay-put company-pseudo-tooltip-overlay 'before-string
-                 (overlay-get company-pseudo-tooltip-overlay 
'company-before))))
+                 (overlay-get company-pseudo-tooltip-overlay 'company-before))
+    (overlay-put company-pseudo-tooltip-overlay 'window (selected-window))))
 
 (defun company-pseudo-tooltip-frontend (command)
   "A `company-mode' front-end similar to a tool-tip but based on overlays."

commit fd0f96bfe4e058bd50b058cdc9575ebba5d9ffbf
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 13:00:53 2009 +0100

    Added known issue doc.

diff --git a/company.el b/company.el
index 9d25e81..bfe9dcd 100644
--- a/company.el
+++ b/company.el
@@ -49,6 +49,10 @@
 ;;     ('candidates (list "foobar" "foobaz" "foobarbaz"))
 ;;     ('meta (format "This value is named %s" arg))))
 ;;
+;; Known Issues:
+;; When point is at the very end of the buffer, the pseudo-tooltip appears very
+;; wrong.
+;;
 ;;; Change Log:
 ;;
 ;;    Initial release.

commit 3f9cbabcf83be9e5f001bcaf4b5f7abd63372a93
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 12:45:54 2009 +0100

    Made company-elisp work in lisp-interaction-mode.

diff --git a/company-elisp.el b/company-elisp.el
index 4b0e15b..7fcea0c 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -68,7 +68,7 @@
 (defun company-elisp (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `emacs-lisp-mode'."
   (case command
-    ('prefix (and (eq major-mode 'emacs-lisp-mode)
+    ('prefix (and (eq (derived-mode-p 'emacs-lisp-mode) 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
     ('candidates (let ((completion-ignore-case nil))
                    (append (all-completions arg (company-elisp-parse-let))

commit 6985a3a321246e81aaa0de5d1d95ddb08c4f0336
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 12:45:11 2009 +0100

    Added <up> and <down> as keybindings for selecting.

diff --git a/company.el b/company.el
index 7aca3c8..9d25e81 100644
--- a/company.el
+++ b/company.el
@@ -235,6 +235,8 @@ immediately when a prefix of 
`company-minimum-prefix-length' is reached."
   (let ((keymap (make-sparse-keymap)))
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
+    (define-key keymap (kbd "<down>") 'company-select-next)
+    (define-key keymap (kbd "<up>") 'company-select-previous)
     (define-key keymap "\C-m" 'company-complete-selection)
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)

commit 185311af534c65f72c5abb9aa4e82731dfe2dff6
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 12:44:07 2009 +0100

    Changed selection color for low-color displays.

diff --git a/company.el b/company.el
index 84bf46c..7aca3c8 100644
--- a/company.el
+++ b/company.el
@@ -78,8 +78,9 @@
   :group 'company)
 
 (defface company-tooltip-selection
-  '((t :background "orange1"
-       :foreground "black"))
+  '((default :inherit company-tooltip)
+    (((class color) (min-colors 88)) (:background "orange1"))
+    (t (:background "green")))
   "*Face used for the selection in the tool tip."
   :group 'company)
 

commit 7732d9ea39d1f524d343531bc970ab47694cfcdf
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 20 09:30:18 2009 +0100

    Added support for yaooddmuse-mode.

diff --git a/company-oddmuse.el b/company-oddmuse.el
index 936cf88..0cdc93c 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -18,23 +18,29 @@
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 (require 'company)
-(require 'oddmuse)
+(eval-when 'compile (require 'yaooddmuse nil t))
+(eval-when 'compile (require 'oddmuse nil t))
 (eval-when-compile (require 'cl))
 
 (defvar company-oddmuse-link-regexp
   "\\(\\<[A-Z][[:alnum:]]*\\>\\)\\|\\[\\[\\([[:alnum:]]+\\>\\|\\)")
 
+(defun company-oddmuse-get-page-table ()
+  (case major-mode
+    ('yaoddmuse-mode (with-no-warnings
+                       (yaoddmuse-get-pagename-table yaoddmuse-wikiname)))
+    ('oddmuse-mode (with-no-warnings
+                     (oddmuse-make-completion-table oddmuse-wiki)))))
+
 (defun company-oddmuse (command &optional arg &rest ignored)
   "A `company-mode' completion back-end for `oddmuse-mode'."
   (case command
     ('prefix (let ((case-fold-search nil))
-               (and (eq major-mode 'oddmuse-mode)
+               (and (memq major-mode '(oddmuse-mode yaoddmuse-mode))
                     (looking-back company-oddmuse-link-regexp (point-at-bol))
                     (or (match-string 1)
                         (match-string 2)))))
-    ('candidates (all-completions arg
-                                  (oddmuse-make-completion-table 
oddmuse-wiki)))
-    ))
+    ('candidates (all-completions arg (company-oddmuse-get-page-table)))))
 
 (provide 'company-oddmuse)
 ;;; company-oddmuse.el ends here

commit 7ac4f8749577593ac252ffadb646bceacd8aba98
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 22:47:52 2009 +0100

    Show errors when using commands without activating company.

diff --git a/company.el b/company.el
index e30075d..84bf46c 100644
--- a/company.el
+++ b/company.el
@@ -62,6 +62,8 @@
 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^No documentation available$")
+(add-to-list 'debug-ignored-errors "^Company not enabled$")
+(add-to-list 'debug-ignored-errors "^Company not in search mode$")
 
 (defgroup company nil
   "Extensible inline text completion mechanism"
@@ -450,6 +452,7 @@ keymap during active completions:
            (company-post-command)))))
 
 (defun company-manual-begin ()
+  (unless company-mode (error "Company not enabled"))
   (and company-mode
        (not company-candidates)
        (let ((company-idle-delay t)
@@ -573,6 +576,8 @@ keymap during active completions:
 
 (defun company-search-printing-char ()
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (setq company-search-string
         (concat (or company-search-string "") (string last-command-event))
         company-search-lighter (concat " Search: \"" company-search-string
@@ -586,6 +591,8 @@ keymap during active completions:
 (defun company-search-repeat-forward ()
   "Repeat the incremental search in completion candidates forward."
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (let ((pos (company-search company-search-string
                               (cdr (nthcdr company-selection
                                            company-candidates)))))
@@ -596,6 +603,8 @@ keymap during active completions:
 (defun company-search-repeat-backward ()
   "Repeat the incremental search in completion candidates backwards."
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (let ((pos (company-search company-search-string
                               (nthcdr (- company-candidates-length
                                          company-selection)
@@ -614,6 +623,8 @@ keymap during active completions:
 (defun company-search-kill-others ()
   "Limit the completion candidates to the ones matching the search string."
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (let ((predicate (company-create-match-predicate company-search-string)))
     (setq company-candidates-predicate predicate)
     (company-update-candidates (company-apply-predicate company-candidates
@@ -624,11 +635,15 @@ keymap during active completions:
 (defun company-search-abort ()
   "Abort searching the completion candidates."
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (company-set-selection company-search-old-selection t)
   (company-search-mode 0))
 
 (defun company-search-other-char ()
   (interactive)
+  (unless company-mode (error "Company not enabled"))
+  (unless company-search-mode (error "Company not in search mode"))
   (company-search-mode 0)
   (when last-input-event
     (clear-this-command-keys t)
@@ -791,7 +806,8 @@ when the selection has been changed, the selected candidate 
is completed."
 (defun company-show-doc-buffer ()
   "Temporarily show a buffer with the complete documentation for the 
selection."
   (interactive)
-  (when company-candidates
+  (unless company-mode (error "Company not enabled"))
+  (when (company-manual-begin)
     (save-window-excursion
       (let* ((height (window-height))
              (row (cdr (posn-col-row (posn-at-point))))

commit 89f4f98309cef3708f61489594f5660106e942dc
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 20:55:08 2009 +0100

    Added documentation strings.

diff --git a/company-css.el b/company-css.el
index 44ec09f..524c481 100644
--- a/company-css.el
+++ b/company-css.el
@@ -272,6 +272,7 @@ Returns \"\" if no property found, but feasible at this 
position."
   "A regular expression matching CSS tags")
 
 (defun company-css (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for `css-mode'."
   (case command
     ('prefix (and (eq major-mode 'css-mode)
                   (or (company-grab company-css-tag-regexp 1)
diff --git a/company-dabbrev.el b/company-dabbrev.el
index ecd8610..bc6a4dc 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -30,6 +30,7 @@
         (buffer-substring-no-properties (point) end)))))
 
 (defun company-dabbrev (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for `dabbrev-completion'."
   (case command
     ('prefix (company-grab-dabbrev-prefix))
     ('candidates (let ((dabbrev-check-other-buffers))
diff --git a/company-elisp.el b/company-elisp.el
index 5ec3b0a..4b0e15b 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -66,6 +66,7 @@
          (match-string 0 doc))))
 
 (defun company-elisp (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for `emacs-lisp-mode'."
   (case command
     ('prefix (and (eq major-mode 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
diff --git a/company-files.el b/company-files.el
index abb2a00..adbdf90 100644
--- a/company-files.el
+++ b/company-files.el
@@ -57,6 +57,7 @@
     (cdr company-files-completion-cache)))
 
 (defun company-files (command &optional arg &rest ignored)
+  "a `company-mode' completion back-end existing file names."
   (case command
     ('prefix (company-files-grab-existing-name))
     ('candidates (company-files-complete arg))
diff --git a/company-gtags.el b/company-gtags.el
index 607ae39..f5ca914 100644
--- a/company-gtags.el
+++ b/company-gtags.el
@@ -58,6 +58,7 @@
       (nreverse tags))))
 
 (defun company-gtags (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for GNU Global."
   (case command
     ('prefix (and (memq major-mode company-gtags-modes)
                   (company-gtags-available)
diff --git a/company-ispell.el b/company-ispell.el
index 14bdba3..3d5a7ae 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -42,6 +42,7 @@ If nil, use `ispell-complete-word-dict'."
   company-ispell-available)
 
 (defun company-ispell (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end using ispell."
   (case command
     ('prefix (when (company-ispell-available)
                (company-grab "\\<\\w+\\>")))
diff --git a/company-nxml.el b/company-nxml.el
index 72cb234..6ebcedc 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -103,6 +103,7 @@
                            (rng-match-possible-value-strings))))))))
 
 (defun company-nxml (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for `nxml-mode'."
   (case command
     ('prefix (or (company-nxml-tag 'prefix)
                  (company-nxml-attribute 'prefix)
diff --git a/company-oddmuse.el b/company-oddmuse.el
index d9602dd..936cf88 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -25,6 +25,7 @@
   "\\(\\<[A-Z][[:alnum:]]*\\>\\)\\|\\[\\[\\([[:alnum:]]+\\>\\|\\)")
 
 (defun company-oddmuse (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end for `oddmuse-mode'."
   (case command
     ('prefix (let ((case-fold-search nil))
                (and (eq major-mode 'oddmuse-mode)
diff --git a/company-semantic.el b/company-semantic.el
index ad1ab65..c2f6185 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -62,6 +62,7 @@
       (all-completions prefix (semantic-ia-get-completions context (point))))))
 
 (defun company-semantic (command &optional arg &rest ignored)
+  "A `company-mode' completion back-end using CEDET Semantic."
   (case command
     ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
                   (not (company-in-string-or-comment))
diff --git a/company.el b/company.el
index 5650c89..e30075d 100644
--- a/company.el
+++ b/company.el
@@ -25,6 +25,30 @@
 ;;
 ;;; Commentary:
 ;;
+;; Company is a modular completion mechanism.  Modules for retrieving 
completion
+;; candidates are called back-ends, modules for displaying them are front-ends.
+;;
+;; Company comes with many back-ends, e.g. `company-elisp'.  These are
+;; distributed in individual files and can be used individually.
+;;
+;; Place company.el and the back-ends you want to use in a directory and add 
the
+;; following to your .emacs:
+;; (add-to-list 'load-path "/path/to/company")
+;; (autoload 'company-mode "company" nil t)
+;;
+;; Enable company-mode with M-x company-mode.  For further information look at
+;; the documentation for `company-mode' (C-h f company-mode RET)
+;;
+;; To write your own back-end, look at the documentation for 
`company-backends'.
+;; Here is a simple example completing "foo":
+;;
+;; (defun company-my-backend (command &optional arg &rest ignored)
+;;   (case command
+;;     ('prefix (when (looking-back "foo\\>")
+;;                (match-string 0)))
+;;     ('candidates (list "foobar" "foobaz" "foobarbaz"))
+;;     ('meta (format "This value is named %s" arg))))
+;;
 ;;; Change Log:
 ;;
 ;;    Initial release.
@@ -40,7 +64,7 @@
 (add-to-list 'debug-ignored-errors "^No documentation available$")
 
 (defgroup company nil
-  ""
+  "Extensible inline text completion mechanism"
   :group 'abbrev
   :group 'convenience
   :group 'maching)
@@ -48,52 +72,52 @@
 (defface company-tooltip
   '((t :background "yellow"
        :foreground "black"))
-  "*"
+  "*Face used for the tool tip."
   :group 'company)
 
 (defface company-tooltip-selection
   '((t :background "orange1"
        :foreground "black"))
-  "*"
+  "*Face used for the selection in the tool tip."
   :group 'company)
 
 (defface company-tooltip-common
   '((t :inherit company-tooltip
        :foreground "red"))
-  "*"
+  "*Face used for the common completion in the tool tip."
   :group 'company)
 
 (defface company-tooltip-common-selection
   '((t :inherit company-tooltip-selection
        :foreground "red"))
-  "*"
+  "*Face used for the selected common completion in the tool tip."
   :group 'company)
 
 (defcustom company-tooltip-limit 10
-  "*"
+  "*The maximum number of candidates in the tool tip"
   :group 'company
   :type 'integer)
 
 (defface company-preview
   '((t :background "blue4"
        :foreground "wheat"))
-  "*"
+  "*Face used for the completion preview."
   :group 'company)
 
 (defface company-preview-common
   '((t :inherit company-preview
        :foreground "red"))
-  "*"
+  "*Face used for the common part of the completion preview."
   :group 'company)
 
 (defface company-echo nil
-  "*"
+  "*Face used for completions in the echo area."
   :group 'company)
 
 (defface company-echo-common
   '((((background dark)) (:foreground "firebrick1"))
     (((background light)) (:background "firebrick4")))
-  "*"
+  "*Face used for the common part of completions in the echo area."
   :group 'company)
 
 (defun company-frontends-set (variable value)
@@ -118,7 +142,25 @@
 (defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
                                company-preview-if-just-one-frontend
                                company-echo-metadata-frontend)
-  "*"
+  "*The list of active front-ends (visualizations).
+Each front-end is a function that takes one argument.  It is called with
+one of the following arguments:
+
+'show: When the visualization should start.
+
+'hide: When the visualization should end.
+
+'update: When the data has been updated.
+
+'pre-command: Before every command that is executed while the
+visualization is active.
+
+'post-command: After every command that is executed while the
+visualization is active.
+
+The visualized data is stored in `company-prefix', `company-candidates',
+`company-common', `company-selection', `company-point' and
+`company-search-string'."
   :set 'company-frontends-set
   :group 'company
   :type '(repeat (choice (const :tag "echo" company-echo-frontend)
@@ -134,17 +176,48 @@
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-gtags company-oddmuse
                               company-files company-dabbrev)
-  "*"
+  "*The list of active back-ends (completion engines).
+Each back-end is a function that takes a variable number of arguments.
+The first argument is the command requested from the back-end.  It is one
+of the following:
+
+'prefix: The back-end should return the text to be completed.  It must be
+text immediately before `point'.  Returning nil passes control to the next
+back-end.
+
+'candidates: The second argument is the prefix to be completed.  The
+return value should be a list of candidates that start with the prefix.
+
+Optional commands:
+
+'sorted: The back-end may return t here to indicate that the candidates
+are sorted and will not need to be sorted again.
+
+'no-cache: Usually company doesn't ask for candidates again as completion
+progresses, unless the back-end returns t for this command.  The second
+argument is the latest prefix.
+
+'meta: The second argument is a completion candidate.  The back-end should
+return a (short) documentation string for it.
+
+'doc-buffer: The second argument is a completion candidate.  The back-end 
should
+create a buffer (preferably with `company-doc-buffer'), fill it with
+documentation and return it.
+
+The back-end should return nil for all commands it does not support or
+does not know about."
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
 (defcustom company-minimum-prefix-length 3
-  "*"
+  "*The minimum prefix length for automatic completion."
   :group 'company
   :type '(integer :tag "prefix length"))
 
 (defcustom company-idle-delay .7
-  "*"
+  "*The idle delay in seconds until automatic completions starts.
+A value of nil means never complete automatically, t means complete
+immediately when a prefix of `company-minimum-prefix-length' is reached."
   :group 'company
   :type '(choice (const :tag "never (nil)" nil)
                  (const :tag "immediate (t)" t)
@@ -152,7 +225,8 @@
 
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-mode-map (make-sparse-keymap))
+(defvar company-mode-map (make-sparse-keymap)
+  "Keymap used by `company-mode'.")
 
 (defvar company-active-map
   (let ((keymap (make-sparse-keymap)))
@@ -162,11 +236,30 @@
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     (define-key keymap "\C-s" 'company-search-candidates)
-    keymap))
+    keymap)
+  "Keymap that is enabled during an active completion.")
 
 ;;;###autoload
 (define-minor-mode company-mode
-  ""
+  "\"complete anything\"; in in-buffer completion framework.
+Completion starts automatically, depending on the values
+`company-idle-delay' and `company-minimum-prefix-length'
+
+Completion can be controlled with the commands:
+`company-complete-common', `company-complete-selection', `company-complete',
+`company-select-next', `company-select-previous'.
+
+Completions can be searched with `company-search-candidates'.
+
+The completion data is retrieved using `company-backends' and displayed using
+`company-frontends'.
+
+regular keymap:
+
+\\{company-mode-map}
+keymap during active completions:
+
+\\{company-active-map}"
   nil " comp" company-mode-map
   (if company-mode
       (progn
@@ -491,6 +584,7 @@
       (company-set-selection (+ company-selection pos) t))))
 
 (defun company-search-repeat-forward ()
+  "Repeat the incremental search in completion candidates forward."
   (interactive)
   (let ((pos (company-search company-search-string
                               (cdr (nthcdr company-selection
@@ -500,6 +594,7 @@
       (company-set-selection (+ company-selection pos 1) t))))
 
 (defun company-search-repeat-backward ()
+  "Repeat the incremental search in completion candidates backwards."
   (interactive)
   (let ((pos (company-search company-search-string
                               (nthcdr (- company-candidates-length
@@ -517,6 +612,7 @@
         `(string-match ,company-search-string candidate))))
 
 (defun company-search-kill-others ()
+  "Limit the completion candidates to the ones matching the search string."
   (interactive)
   (let ((predicate (company-create-match-predicate company-search-string)))
     (setq company-candidates-predicate predicate)
@@ -526,6 +622,7 @@
     (company-call-frontends 'update)))
 
 (defun company-search-abort ()
+  "Abort searching the completion candidates."
   (interactive)
   (company-set-selection company-search-old-selection t)
   (company-search-mode 0))
@@ -568,10 +665,21 @@
     (define-key keymap "\C-s" 'company-search-repeat-forward)
     (define-key keymap "\C-r" 'company-search-repeat-backward)
     (define-key keymap "\C-o" 'company-search-kill-others)
-    keymap))
+    keymap)
+  "Keymap used for incrementally searching the completion candidates.")
 
 (define-minor-mode company-search-mode
-  ""
+  "Start searching the completion candidates incrementally.
+
+\\<company-search-map>Search can be controlled with the commands:
+- `company-search-repeat-forward' (\\[company-search-repeat-forward])
+- `company-search-repeat-backward' (\\[company-search-repeat-backward])
+- `company-search-abort' (\\[company-search-abort])
+
+Regular characters are appended to the search string.
+
+The command `company-search-kill-others' (\\[company-search-kill-others]) uses
+ the search string to limit the completion candidates."
   nil company-search-lighter nil
   (if company-search-mode
       (if (company-manual-begin)
@@ -586,33 +694,51 @@
     (company-enable-overriding-keymap company-active-map)))
 
 (defun company-search-candidates ()
+  "Start searching the completion candidates incrementally.
+
+\\<company-search-map>Search can be controlled with the commands:
+- `company-search-repeat-forward' (\\[company-search-repeat-forward])
+- `company-search-repeat-backward' (\\[company-search-repeat-backward])
+- `company-search-abort' (\\[company-search-abort])
+
+Regular characters are appended to the search string.
+
+The command `company-search-kill-others' (\\[company-search-kill-others]) uses
+ the search string to limit the completion candidates."
   (interactive)
   (company-search-mode 1))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun company-select-next ()
+  "Select the next candidate in the list."
   (interactive)
   (when (company-manual-begin)
     (company-set-selection (1+ company-selection))))
 
 (defun company-select-previous ()
+  "Select the previous candidate in the list."
   (interactive)
   (when (company-manual-begin)
     (company-set-selection (1- company-selection))))
 
 (defun company-complete-selection ()
+  "Complete the selected candidate."
   (interactive)
   (when (company-manual-begin)
     (insert (company-strip-prefix (nth company-selection company-candidates)))
     (company-abort)))
 
 (defun company-complete-common ()
+  "Complete the common part of all candidates."
   (interactive)
   (when (company-manual-begin)
     (insert (company-strip-prefix company-common))))
 
 (defun company-complete ()
+  "Complete the common part of all candidates or the current selection.
+The first time this is called, the common part is completed, the second time, 
or
+when the selection has been changed, the selected candidate is completed."
   (interactive)
   (when (company-manual-begin)
     (if (or company-selection-changed
@@ -663,6 +789,7 @@
     (current-buffer)))
 
 (defun company-show-doc-buffer ()
+  "Temporarily show a buffer with the complete documentation for the 
selection."
   (interactive)
   (when company-candidates
     (save-window-excursion
@@ -892,6 +1019,7 @@
                  (overlay-get company-pseudo-tooltip-overlay 
'company-before))))
 
 (defun company-pseudo-tooltip-frontend (command)
+  "A `company-mode' front-end similar to a tool-tip but based on overlays."
   (case command
     ('pre-command (company-pseudo-tooltip-hide-temporarily))
     ('post-command
@@ -910,6 +1038,7 @@
                                             company-selection)))))
 
 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
+  "`company-pseudo-tooltip-frontend', but not shown for single candidates."
   (unless (and (eq command 'post-command)
                (not (cdr company-candidates)))
     (company-pseudo-tooltip-frontend command)))
@@ -943,12 +1072,14 @@
     (setq company-preview-overlay nil)))
 
 (defun company-preview-frontend (command)
+  "A `company-mode' front-end showing the selection as if it had been 
inserted."
   (case command
     ('pre-command (company-preview-hide))
     ('post-command (company-preview-show-at-point (point)))
     ('hide (company-preview-hide))))
 
 (defun company-preview-if-just-one-frontend (command)
+  "`company-preview-frontend', but only shown for single candidates."
   (unless (and (eq command 'post-command)
                (cdr company-candidates))
     (company-preview-frontend command)))
@@ -1003,12 +1134,14 @@
   (company-echo-show))
 
 (defun company-echo-frontend (command)
+  "A `company-mode' front-end showing the candidates in the echo area."
   (case command
     ('pre-command (company-echo-show-soon))
     ('post-command (company-echo-show-soon 'company-echo-format))
     ('hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
+  "A `company-mode' front-end showing the documentation in the echo area."
   (case command
     ('pre-command (company-echo-show-soon))
     ('post-command (company-echo-show-soon 'company-fetch-metadata))

commit 2925dc36272f91ee3a7120a59e3dae39116458cd
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 21:37:13 2009 +0100

    Deal with missing ispell look command.

diff --git a/company-ispell.el b/company-ispell.el
index b5b1a61..14bdba3 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -28,9 +28,23 @@ If nil, use `ispell-complete-word-dict'."
   :type '(choice (const :tag "default (nil)" nil)
                  (file :tag "dictionary" t)))
 
+(defvar company-ispell-available 'unknown)
+
+(defun company-ispell-available ()
+  (when (eq company-ispell-available 'unknown)
+    (condition-case err
+        (progn
+          (lookup-words "WHATEVER")
+          (setq company-ispell-available t))
+      (error
+       (message "Company: ispell-look-command not found")
+       (setq company-ispell-available nil))))
+  company-ispell-available)
+
 (defun company-ispell (command &optional arg &rest ignored)
   (case command
-    ('prefix (company-grab "\\<\\w+\\>"))
+    ('prefix (when (company-ispell-available)
+               (company-grab "\\<\\w+\\>")))
     ('candidates (lookup-words arg (or company-ispell-dictionary
                                        ispell-complete-word-dict)))
     ('sorted t)

commit 7f415a0bbb5a33c71b32ca276bf8a21154c8fa6e
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 18:21:41 2009 +0100

    Made search map compatible to Emacs 22.

diff --git a/company.el b/company.el
index f632baa..5650c89 100644
--- a/company.el
+++ b/company.el
@@ -540,8 +540,16 @@
 (defvar company-search-map
   (let ((i 0)
         (keymap (make-keymap)))
-    (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
-                          'company-search-printing-char)
+    (if (fboundp 'max-char)
+        (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
+                              'company-search-printing-char)
+      (with-no-warnings
+        ;; obselete in Emacs 23
+        (let ((l (generic-character-list))
+              (table (nth 1 keymap)))
+          (while l
+            (set-char-table-default table (car l) 'isearch-printing-char)
+            (setq l (cdr l))))))
     (define-key keymap [t] 'company-search-other-char)
     (while (< i ?\s)
       (define-key keymap (make-string 1 i) 'company-search-other-char)

commit 789bd4b523ee4c8d1f90a60a8ee87537aaab7f21
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 18:24:24 2009 +0100

    Added support for chained predicates.

diff --git a/company.el b/company.el
index 628ced9..f632baa 100644
--- a/company.el
+++ b/company.el
@@ -509,10 +509,16 @@
         (ding)
       (company-set-selection (- company-selection pos 1) t))))
 
+(defsubst company-create-match-predicate (search-string)
+  `(lambda (candidate)
+     ,(if company-candidates-predicate
+          `(and (string-match ,search-string candidate)
+                (funcall ,company-candidates-predicate candidate))
+        `(string-match ,company-search-string candidate))))
+
 (defun company-search-kill-others ()
   (interactive)
-  (let ((predicate `(lambda (candidate)
-                      (string-match ,company-search-string candidate))))
+  (let ((predicate (company-create-match-predicate company-search-string)))
     (setq company-candidates-predicate predicate)
     (company-update-candidates (company-apply-predicate company-candidates
                                                         predicate))

commit 044bf06af94ea9f45029161ee631ac559d0945f2
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 14:03:46 2009 +0100

    Speed up line replacement.

diff --git a/company-gtags.el b/company-gtags.el
new file mode 100644
index 0000000..607ae39
--- /dev/null
+++ b/company-gtags.el
@@ -0,0 +1,71 @@
+;;; company-gtags.el --- a company-mode completion back-end for GNU Global
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defcustom company-gtags-gnu-global-program-name
+  (or (locate-file "global" exec-path exec-suffixes 'file-executable-p)
+      "global")
+  "*"
+  :type 'string
+  :group 'company)
+
+(defvar company-gtags-symbol-regexp
+  "\\_<[A-Za-z_][A-Za-z_0-9]*\\_>")
+
+(defvar company-gtags-modes '(c-mode c++-mode jde-mode java-mode php-mode))
+
+(defvar company-gtags-available 'unknown)
+(make-variable-buffer-local 'company-gtags-available)
+
+(defun company-gtags-available ()
+  (when (eq company-gtags-available 'unknown)
+    (condition-case err
+        (setq company-gtags-available
+              (= 0 (call-process company-gtags-gnu-global-program-name
+                                 nil nil nil "-c" "WHATEVER")))
+      (error
+       (message "Company: GNU Global not found")
+       (setq-default company-gtags-available nil))))
+  company-gtags-available)
+
+(defun company-gtags-fetch-tags (prefix)
+  (with-temp-buffer
+    (let (tags)
+      (when (= 0 (call-process "global" nil (list (current-buffer) nil)
+                               nil "-c" prefix))
+        (goto-char (point-min))
+        (while (looking-at company-gtags-symbol-regexp)
+          (push (match-string-no-properties 0) tags)
+          (forward-line)))
+      (nreverse tags))))
+
+(defun company-gtags (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (memq major-mode company-gtags-modes)
+                  (company-gtags-available)
+               (or (company-grab company-gtags-symbol-regexp) "")))
+    ('candidates (company-gtags-fetch-tags arg))
+    ('sorted t)))
+
+(provide 'company-gtags)
+;;; company-gtags.el ends here
+
+
diff --git a/company.el b/company.el
index 45a94d8..628ced9 100644
--- a/company.el
+++ b/company.el
@@ -132,7 +132,7 @@
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-oddmuse
+                              company-semantic company-gtags company-oddmuse
                               company-files company-dabbrev)
   "*"
   :group 'company
@@ -748,7 +748,7 @@
       (push (buffer-substring beg end) lines))
     (nreverse lines)))
 
-(defun company-modify-line (old new offset)
+(defsubst company-modify-line (old new offset)
   (concat (company-safe-substring old 0 offset)
           new
           (company-safe-substring old (+ offset (length new)))))
@@ -760,7 +760,7 @@
       (push (company-modify-line (pop old) (pop lines) column) new))
     ;; Append whole new lines.
     (while lines
-      (push (company-modify-line "" (pop lines) column) new))
+      (push (concat (company-space-string column) (pop lines)) new))
     (concat (when nl "\n")
             (mapconcat 'identity (nreverse new) "\n")
             "\n")))

commit 8bbb459317ab28eaa328670781731f973e31f14b
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 13:47:03 2009 +0100

    Calculate window line number faster.
    
    This makes scrolling 20% faster.

diff --git a/company.el b/company.el
index e098327..45a94d8 100644
--- a/company.el
+++ b/company.el
@@ -817,7 +817,8 @@
 (defsubst company-pseudo-tooltip-height ()
   "Calculate the appropriate tooltip height."
   (max 3 (min company-tooltip-limit
-              (- (window-height) (cdr (posn-col-row (posn-at-point))) 2))))
+              (- (window-height) 2
+                 (count-lines (window-start) (point-at-bol))))))
 
 (defun company-pseudo-tooltip-show (row column selection)
   (company-pseudo-tooltip-hide)

commit 2cf5e0b288d1483bc1c0b9e20948b61014672cdb
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 19 13:01:13 2009 +0100

    Don't bother with cache, if it is empty.

diff --git a/company.el b/company.el
index b812385..e098327 100644
--- a/company.el
+++ b/company.el
@@ -322,18 +322,19 @@
   (setq company-prefix prefix)
   (company-update-candidates
    (or (cdr (assoc prefix company-candidates-cache))
-       (let ((len (length prefix))
-             (completion-ignore-case (funcall company-backend 'ignore-case))
-             prev)
-         (dotimes (i len)
-           (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
-                                        company-candidates-cache)))
-             (return (all-completions prefix prev)))))
+       (when company-candidates-cache
+         (let ((len (length prefix))
+               (completion-ignore-case (funcall company-backend 'ignore-case))
+               prev)
+           (dotimes (i len)
+             (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                          company-candidates-cache)))
+               (return (all-completions prefix prev))))))
        (let ((candidates (funcall company-backend 'candidates prefix)))
-         (and company-candidates-predicate
-              (setq candidates
-                    (company-apply-predicate candidates
-                                             company-candidates-predicate)))
+         (when company-candidates-predicate
+           (setq candidates
+                 (company-apply-predicate candidates
+                                          company-candidates-predicate)))
          (unless (funcall company-backend 'sorted)
            (setq candidates (sort candidates 'string<)))
          candidates)))

commit 94bd2cf31dd21355311983e9397c9b0acf8354fb
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 18 09:53:15 2009 +0100

    Speed up echo by not showing it immediately.

diff --git a/company.el b/company.el
index 33ba6fa..b812385 100644
--- a/company.el
+++ b/company.el
@@ -942,20 +942,32 @@
 (defvar company-echo-last-msg nil)
 (make-variable-buffer-local 'company-echo-last-msg)
 
-(defun company-echo-refresh ()
+(defvar company-echo-timer nil)
+
+(defvar company-echo-delay .1)
+
+(defun company-echo-show (&optional getter)
+  (when getter
+    (setq company-echo-last-msg (funcall getter)))
   (let ((message-log-max nil))
     (if company-echo-last-msg
         (message "%s" company-echo-last-msg)
       (message ""))))
 
-(defun company-echo-show (candidates)
+(defsubst company-echo-show-soon (&optional getter)
+  (when company-echo-timer
+    (cancel-timer company-echo-timer))
+  (setq company-echo-timer (run-with-timer company-echo-delay nil
+                                           'company-echo-show getter)))
 
-  ;; Roll to selection.
-  (setq candidates (nthcdr company-selection candidates))
+(defun company-echo-format ()
 
   (let ((limit (window-width (minibuffer-window)))
         (len -1)
+        ;; Roll to selection.
+        (candidates (nthcdr company-selection company-candidates))
         comp msg)
+
     (while candidates
       (setq comp (company-reformat (pop candidates))
             len (+ len 1 (length comp)))
@@ -966,22 +978,25 @@
                              '(face company-echo-common) comp)
         (push comp msg)))
 
-    (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
-    (company-echo-refresh)))
+    (mapconcat 'identity (nreverse msg) " ")))
+
+(defun company-echo-hide ()
+  (when company-echo-timer
+    (cancel-timer company-echo-timer))
+  (setq company-echo-last-msg "")
+  (company-echo-show))
 
 (defun company-echo-frontend (command)
   (case command
-    ('pre-command (company-echo-refresh))
-    ('post-command (company-echo-show company-candidates))
-    ('hide (setq company-echo-last-msg nil))))
+    ('pre-command (company-echo-show-soon))
+    ('post-command (company-echo-show-soon 'company-echo-format))
+    ('hide (company-echo-hide))))
 
 (defun company-echo-metadata-frontend (command)
   (case command
-    ('pre-command (company-echo-refresh))
-    ('post-command (setq company-echo-last-msg (company-fetch-metadata))
-                   (company-echo-refresh))
-    ('hide (setq company-echo-last-msg nil))))
-
+    ('pre-command (company-echo-show-soon))
+    ('post-command (company-echo-show-soon 'company-fetch-metadata))
+    ('hide (company-echo-hide))))
 
 (provide 'company)
 ;;; company.el ends here

commit e7707ffde4cabe493a2e0d058a8e5700f1f399a0
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 18 09:24:53 2009 +0100

    Speed up scrolling by calculating the candidates length earlier.

diff --git a/company.el b/company.el
index ce6c11d..33ba6fa 100644
--- a/company.el
+++ b/company.el
@@ -238,6 +238,9 @@
 (defvar company-candidates nil)
 (make-variable-buffer-local 'company-candidates)
 
+(defvar company-candidates-length nil)
+(make-variable-buffer-local 'company-candidates-length)
+
 (defvar company-candidates-cache nil)
 (make-variable-buffer-local 'company-candidates-cache)
 
@@ -280,7 +283,7 @@
                     frontend (error-message-string err) command)))))
 
 (defsubst company-set-selection (selection &optional force-update)
-  (setq selection (max 0 (min (1- (length company-candidates)) selection)))
+  (setq selection (max 0 (min (1- company-candidates-length) selection)))
   (when (or force-update (not (equal selection company-selection)))
     (setq company-selection selection
           company-selection-changed t)
@@ -294,6 +297,7 @@
     (nreverse new)))
 
 (defun company-update-candidates (candidates)
+  (setq company-candidates-length (length candidates))
   (if (> company-selection 0)
       ;; Try to restore the selection
       (let ((selected (nth company-selection company-candidates)))
@@ -304,7 +308,7 @@
             (incf company-selection))
           (unless candidates
             ;; Make sure selection isn't out of bounds.
-            (setq company-selection (min (1- (length company-candidates))
+            (setq company-selection (min (1- company-candidates-length)
                                          company-selection)))))
     (setq company-selection 0
           company-candidates candidates))
@@ -403,6 +407,7 @@
   (setq company-backend nil
         company-prefix nil
         company-candidates nil
+        company-candidates-length nil
         company-candidates-cache nil
         company-candidates-predicate nil
         company-common nil
@@ -496,7 +501,7 @@
 (defun company-search-repeat-backward ()
   (interactive)
   (let ((pos (company-search company-search-string
-                              (nthcdr (- (length company-candidates)
+                              (nthcdr (- company-candidates-length
                                          company-selection)
                                       (reverse company-candidates)))))
     (if (null pos)
@@ -759,9 +764,10 @@
             (mapconcat 'identity (nreverse new) "\n")
             "\n")))
 
-(defun company-create-lines (column lines selection limit)
+(defun company-create-lines (column selection limit)
 
-  (let ((len (length lines))
+  (let ((len company-candidates-length)
+        lines
         width
         lines-copy
         previous
@@ -780,8 +786,8 @@
 
     (decf selection company-tooltip-offset)
     (setq width (min (length previous) (length remainder))
-          lines (nthcdr company-tooltip-offset lines)
-          len (min limit (length lines))
+          lines (nthcdr company-tooltip-offset company-candidates)
+          len (min limit len)
           lines-copy lines)
 
     (dotimes (i len)
@@ -812,15 +818,14 @@
   (max 3 (min company-tooltip-limit
               (- (window-height) (cdr (posn-col-row (posn-at-point))) 2))))
 
-(defun company-pseudo-tooltip-show (row column lines selection)
+(defun company-pseudo-tooltip-show (row column selection)
   (company-pseudo-tooltip-hide)
-  (unless lines (error "No text provided"))
   (save-excursion
 
     (move-to-column 0)
 
     (let* ((height (company-pseudo-tooltip-height))
-           (lines (company-create-lines column lines selection height))
+           (lines (company-create-lines column selection height))
            (nl (< (move-to-window-line row) row))
            (beg (point))
            (end (save-excursion
@@ -843,15 +848,14 @@
 
 (defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (posn-col-row (posn-at-point pos))))
-    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
-                                 company-candidates company-selection)))
+    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row) 
company-selection)))
 
 (defun company-pseudo-tooltip-edit (lines selection)
   (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
          (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
          (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
          (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
-         (lines (company-create-lines column lines selection height)))
+         (lines (company-create-lines column selection height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (company-replacement-string old-string lines column nl))))
 

commit b775519e3cafc1729e6112313317b3a9535c685a
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 18 08:58:27 2009 +0100

    Deal with tabs.

diff --git a/company.el b/company.el
index 4a79875..ce6c11d 100644
--- a/company.el
+++ b/company.el
@@ -694,6 +694,18 @@
 
 ;;; propertize
 
+(defsubst company-round-tab (arg)
+  (* (/ (+ arg tab-width) tab-width) tab-width))
+
+(defun company-untabify (str)
+  (let* ((pieces (split-string str "\t"))
+         (copy pieces))
+    (while (cdr copy)
+      (setcar copy (company-safe-substring
+                    (car copy) 0 (company-round-tab (string-width (car 
copy)))))
+      (pop copy))
+    (apply 'concat pieces)))
+
 (defun company-fill-propertize (line width selected)
   (setq line (company-safe-substring line 0 width))
   (add-text-properties 0 width (list 'face 'company-tooltip) line)
@@ -814,7 +826,8 @@
            (end (save-excursion
                   (move-to-window-line (+ row height))
                   (point)))
-           (old-string (company-buffer-lines beg end))
+           (old-string
+            (mapcar 'company-untabify (company-buffer-lines beg end)))
            str)
 
       (setq company-pseudo-tooltip-overlay (make-overlay beg end))

commit 5689d6b93cd757572cafe340a5b42f6fef1887d9
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 17 14:29:19 2009 +0100

    Deal with empty prefixes in semantic.

diff --git a/company-semantic.el b/company-semantic.el
index a310927..ad1ab65 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -72,7 +72,8 @@
     ('meta (funcall company-semantic-metadata-function
                     (semantic-analyze-find-tag arg)))
     ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))
-    ))
+    ;; because "" is an empty context and doesn't return local variables
+    ('no-cache (equal arg ""))))
 
 (provide 'company-semantic)
 ;;; company-semantic.el ends here
diff --git a/company.el b/company.el
index 2859cb9..4a79875 100644
--- a/company.el
+++ b/company.el
@@ -362,7 +362,7 @@
 
 (defun company-continue ()
   (when company-candidates
-    (when (funcall company-backend 'no-cache)
+    (when (funcall company-backend 'no-cache company-prefix)
       ;; Don't complete existing candidates, fetch new ones.
       (setq company-candidates-cache nil))
     (let ((new-prefix (funcall company-backend 'prefix)))

commit 19f1bc89786de9a0fe52fb9cbc276fcbf23bedc3
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 17 13:54:39 2009 +0100

    Protect against front-end errors.

diff --git a/company.el b/company.el
index 5ea0925..2859cb9 100644
--- a/company.el
+++ b/company.el
@@ -274,7 +274,10 @@
 
 (defsubst company-call-frontends (command)
   (dolist (frontend company-frontends)
-    (funcall frontend command)))
+    (condition-case err
+        (funcall frontend command)
+      (error (error "Company: Front-end %s error \"%s\" on command %s"
+                    frontend (error-message-string err) command)))))
 
 (defsubst company-set-selection (selection &optional force-update)
   (setq selection (max 0 (min (1- (length company-candidates)) selection)))

commit c55a56b5d862cb3e7a9e506297e58cf4bda0ab7f
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 17 13:51:01 2009 +0100

    Switched to regular timer, because idle time fluctuates too much.

diff --git a/company.el b/company.el
index 91cdfc1..5ea0925 100644
--- a/company.el
+++ b/company.el
@@ -143,17 +143,8 @@
   :group 'company
   :type '(integer :tag "prefix length"))
 
-(defvar company-timer nil)
-
-(defun company-timer-set (variable value)
-  (set variable value)
-  (when company-timer (cancel-timer company-timer))
-  (when (numberp value)
-    (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
-
 (defcustom company-idle-delay .7
   "*"
-  :set 'company-timer-set
   :group 'company
   :type '(choice (const :tag "never (nil)" nil)
                  (const :tag "immediate (t)" t)
@@ -180,9 +171,7 @@
   (if company-mode
       (progn
         (add-hook 'pre-command-hook 'company-pre-command nil t)
-        (add-hook 'post-command-hook 'company-post-command nil t)
-        (company-timer-set 'company-idle-delay
-                           company-idle-delay))
+        (add-hook 'post-command-hook 'company-post-command nil t))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
     (company-cancel)
@@ -267,6 +256,8 @@
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
+(defvar company-timer nil)
+
 (defvar company-disabled-backends nil)
 
 (defsubst company-strip-prefix (str)
@@ -343,8 +334,12 @@
     (push (cons prefix company-candidates) company-candidates-cache))
   company-candidates)
 
-(defun company-idle-begin ()
+(defun company-idle-begin (buf win tick pos)
   (and company-mode
+       (eq buf (current-buffer))
+       (eq win (selected-window))
+       (eq tick (buffer-chars-modified-tick))
+       (eq pos (point))
        (not company-candidates)
        (not (equal (point) company-point))
        (let ((company-idle-delay t))
@@ -411,6 +406,8 @@
         company-selection 0
         company-selection-changed nil
         company-point nil)
+  (when company-timer
+    (cancel-timer company-timer))
   (company-search-mode 0)
   (company-call-frontends 'hide)
   (company-enable-overriding-keymap nil))
@@ -428,6 +425,8 @@
       (error (message "Company: An error occurred in pre-command")
              (message "%s" (error-message-string err))
              (company-cancel))))
+  (when company-timer
+    (cancel-timer company-timer))
   (company-uninstall-map))
 
 (defun company-post-command ()
@@ -437,7 +436,12 @@
           (unless (equal (point) company-point)
             (company-begin))
           (when company-candidates
-            (company-call-frontends 'post-command)))
+            (company-call-frontends 'post-command))
+          (when (numberp company-idle-delay)
+            (setq company-timer
+                  (run-with-timer company-idle-delay nil 'company-idle-begin
+                                  (current-buffer) (selected-window)
+                                  (buffer-chars-modified-tick) (point)))))
       (error (message "Company: An error occurred in post-command")
              (message "%s" (error-message-string err))
              (company-cancel))))

commit ccac8100bd6e7924d36aa2eda228ce5c03432ab1
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 22:12:40 2009 +0100

    Allowed scrolling of the documentation window.

diff --git a/company.el b/company.el
index 5f7023a..91cdfc1 100644
--- a/company.el
+++ b/company.el
@@ -649,7 +649,9 @@
           (and (< (window-height) height)
                (< (- (window-height) row 2) company-tooltip-limit)
                (recenter (- (window-height) row 2)))
-          (read-event)
+          (while (eq 'scroll-other-window
+                     (key-binding (vector (list (read-event)))))
+            (scroll-other-window))
           (when last-input-event
             (clear-this-command-keys t)
             (setq unread-command-events (list last-input-event))))))))

commit 46a9418d8696b085bac427d00231457ef715a43a
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 22:12:29 2009 +0100

    More efficient filtering.

diff --git a/company.el b/company.el
index 8f17ef9..5f7023a 100644
--- a/company.el
+++ b/company.el
@@ -500,9 +500,11 @@
   (interactive)
   (let ((predicate `(lambda (candidate)
                       (string-match ,company-search-string candidate))))
-    (company-cancel)
     (setq company-candidates-predicate predicate)
-    (company-manual-begin)))
+    (company-update-candidates (company-apply-predicate company-candidates
+                                                        predicate))
+    (company-search-mode 0)
+    (company-call-frontends 'update)))
 
 (defun company-search-abort ()
   (interactive)

commit 70355f3da9f5065e7e6dbf8dd469f524e4a5542b
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 20:36:56 2009 +0100

    Keep selection when updating completions.

diff --git a/company.el b/company.el
index ce55081..8f17ef9 100644
--- a/company.el
+++ b/company.el
@@ -299,32 +299,48 @@
         (push c new)))
     (nreverse new)))
 
-(defsubst company-calculate-candidates (prefix)
-  (or (setq company-candidates (cdr (assoc prefix company-candidates-cache)))
-      (let ((len (length prefix))
-            (completion-ignore-case (funcall company-backend 'ignore-case))
-            prev)
-        (dotimes (i len)
-          (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
-                                       company-candidates-cache)))
-            (setq company-candidates (all-completions prefix prev))
-            (return t))))
-      (progn
-        (setq company-candidates (funcall company-backend 'candidates prefix))
-        (when company-candidates-predicate
-          (setq company-candidates
-                (company-apply-predicate company-candidates
-                                         company-candidates-predicate)))
-        (unless (funcall company-backend 'sorted)
-          (setq company-candidates (sort company-candidates 'string<)))))
-  (unless (assoc prefix company-candidates-cache)
-    (push (cons prefix company-candidates) company-candidates-cache))
-  (setq company-selection 0
-        company-prefix prefix)
+(defun company-update-candidates (candidates)
+  (if (> company-selection 0)
+      ;; Try to restore the selection
+      (let ((selected (nth company-selection company-candidates)))
+        (setq company-selection 0
+              company-candidates candidates)
+        (when selected
+          (while (and candidates (string< (pop candidates) selected))
+            (incf company-selection))
+          (unless candidates
+            ;; Make sure selection isn't out of bounds.
+            (setq company-selection (min (1- (length company-candidates))
+                                         company-selection)))))
+    (setq company-selection 0
+          company-candidates candidates))
+  ;; Calculate common.
   (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
     (setq company-common (try-completion company-prefix company-candidates)))
   (when (eq company-common t)
-    (setq company-candidates nil))
+    (setq company-candidates nil)))
+
+(defsubst company-calculate-candidates (prefix)
+  (setq company-prefix prefix)
+  (company-update-candidates
+   (or (cdr (assoc prefix company-candidates-cache))
+       (let ((len (length prefix))
+             (completion-ignore-case (funcall company-backend 'ignore-case))
+             prev)
+         (dotimes (i len)
+           (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                        company-candidates-cache)))
+             (return (all-completions prefix prev)))))
+       (let ((candidates (funcall company-backend 'candidates prefix)))
+         (and company-candidates-predicate
+              (setq candidates
+                    (company-apply-predicate candidates
+                                             company-candidates-predicate)))
+         (unless (funcall company-backend 'sorted)
+           (setq candidates (sort candidates 'string<)))
+         candidates)))
+  (unless (assoc prefix company-candidates-cache)
+    (push (cons prefix company-candidates) company-candidates-cache))
   company-candidates)
 
 (defun company-idle-begin ()

commit e74d39b47c9a731d1b04e92b2a959194fee0e1ff
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 19:45:54 2009 +0100

    Added command to filter based on search.

diff --git a/company.el b/company.el
index c613e0b..ce55081 100644
--- a/company.el
+++ b/company.el
@@ -252,6 +252,9 @@
 (defvar company-candidates-cache nil)
 (make-variable-buffer-local 'company-candidates-cache)
 
+(defvar company-candidates-predicate nil)
+(make-variable-buffer-local 'company-candidates-predicate)
+
 (defvar company-common nil)
 (make-variable-buffer-local 'company-common)
 
@@ -289,6 +292,13 @@
           company-selection-changed t)
     (company-call-frontends 'update)))
 
+(defun company-apply-predicate (candidates predicate)
+  (let (new)
+    (dolist (c candidates)
+      (when (funcall predicate c)
+        (push c new)))
+    (nreverse new)))
+
 (defsubst company-calculate-candidates (prefix)
   (or (setq company-candidates (cdr (assoc prefix company-candidates-cache)))
       (let ((len (length prefix))
@@ -301,6 +311,10 @@
             (return t))))
       (progn
         (setq company-candidates (funcall company-backend 'candidates prefix))
+        (when company-candidates-predicate
+          (setq company-candidates
+                (company-apply-predicate company-candidates
+                                         company-candidates-predicate)))
         (unless (funcall company-backend 'sorted)
           (setq company-candidates (sort company-candidates 'string<)))))
   (unless (assoc prefix company-candidates-cache)
@@ -376,6 +390,7 @@
         company-prefix nil
         company-candidates nil
         company-candidates-cache nil
+        company-candidates-predicate nil
         company-common nil
         company-selection 0
         company-selection-changed nil
@@ -465,6 +480,14 @@
         (ding)
       (company-set-selection (- company-selection pos 1) t))))
 
+(defun company-search-kill-others ()
+  (interactive)
+  (let ((predicate `(lambda (candidate)
+                      (string-match ,company-search-string candidate))))
+    (company-cancel)
+    (setq company-candidates-predicate predicate)
+    (company-manual-begin)))
+
 (defun company-search-abort ()
   (interactive)
   (company-set-selection company-search-old-selection t)
@@ -499,6 +522,7 @@
     (define-key keymap "\C-g" 'company-search-abort)
     (define-key keymap "\C-s" 'company-search-repeat-forward)
     (define-key keymap "\C-r" 'company-search-repeat-backward)
+    (define-key keymap "\C-o" 'company-search-kill-others)
     keymap))
 
 (define-minor-mode company-search-mode

commit 5690ea9bf81d47cfd28a3e30a54332c6f921092c
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 19:06:17 2009 +0100

    Added files completion.

diff --git a/company-files.el b/company-files.el
new file mode 100644
index 0000000..abb2a00
--- /dev/null
+++ b/company-files.el
@@ -0,0 +1,67 @@
+;;; company-files.el --- a company-mode completion back-end for file names
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defun company-files-directory-files (dir prefix)
+  (ignore-errors
+    (if (equal prefix "")
+        (directory-files dir nil "\\`[^.]\\|\\`.[^.]")
+      (file-name-all-completions prefix dir))))
+
+(defun company-files-grab-existing-name ()
+  ;; Grab file names with spaces, only when they include quotes.
+  (let ((file (or (company-grab "\"\\(~?/[^\"\n]*\\)" 1)
+                  (company-grab "\'\\(~?/[^\'\n]*\\)" 1)
+                  (company-grab "[ \t\n]\\(~?/[^ \t\n]*\\)" 1)))
+        dir)
+    (and file
+         (setq dir (file-name-directory file))
+         (file-exists-p dir)
+         (file-name-all-completions (file-name-nondirectory file) dir)
+         file)))
+
+(defvar company-files-completion-cache nil)
+
+(defun company-files-complete (prefix)
+  (let* ((dir (file-name-directory prefix))
+         (file (file-name-nondirectory prefix))
+         candidates)
+    (setq company-files-completion-cache nil)
+    (unless (equal dir (car company-files-completion-cache))
+      (dolist (file (company-files-directory-files dir file))
+        (setq file (concat dir file))
+        (push file candidates)
+        (when (file-directory-p file)
+          ;; Add one level of children.
+          (dolist (child (company-files-directory-files file ""))
+            (push (concat file child) candidates))))
+      (setq company-files-completion-cache (cons dir (nreverse candidates))))
+    (cdr company-files-completion-cache)))
+
+(defun company-files (command &optional arg &rest ignored)
+  (case command
+    ('prefix (company-files-grab-existing-name))
+    ('candidates (company-files-complete arg))
+    ('sorted t)
+    ('no-cache t)))
+
+(provide 'company-files)
+;;; company-files.el ends here
diff --git a/company.el b/company.el
index 54c8b3b..c613e0b 100644
--- a/company.el
+++ b/company.el
@@ -133,7 +133,7 @@
 
 (defcustom company-backends '(company-elisp company-nxml company-css
                               company-semantic company-oddmuse
-                              company-dabbrev)
+                              company-files company-dabbrev)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))
@@ -334,6 +334,9 @@
 
 (defun company-continue ()
   (when company-candidates
+    (when (funcall company-backend 'no-cache)
+      ;; Don't complete existing candidates, fetch new ones.
+      (setq company-candidates-cache nil))
     (let ((new-prefix (funcall company-backend 'prefix)))
       (unless (and (= (- (point) (length new-prefix))
                       (- company-point (length company-prefix)))

commit a380988a973fee7f3ccd70c30087026cd593da77
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 18:12:33 2009 +0100

    Added candidate search.

diff --git a/company.el b/company.el
index 4fd1b9f..54c8b3b 100644
--- a/company.el
+++ b/company.el
@@ -170,6 +170,7 @@
     (define-key keymap "\C-m" 'company-complete-selection)
     (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
+    (define-key keymap "\C-s" 'company-search-candidates)
     keymap))
 
 ;;;###autoload
@@ -281,9 +282,9 @@
   (dolist (frontend company-frontends)
     (funcall frontend command)))
 
-(defsubst company-set-selection (selection)
+(defsubst company-set-selection (selection &optional force-update)
   (setq selection (max 0 (min (1- (length company-candidates)) selection)))
-  (unless (equal selection company-selection)
+  (when (or force-update (not (equal selection company-selection)))
     (setq company-selection selection
           company-selection-changed t)
     (company-call-frontends 'update)))
@@ -376,6 +377,7 @@
         company-selection 0
         company-selection-changed nil
         company-point nil)
+  (company-search-mode 0)
   (company-call-frontends 'hide)
   (company-enable-overriding-keymap nil))
 
@@ -407,6 +409,114 @@
              (company-cancel))))
   (company-install-map))
 
+;;; search 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-search-string nil)
+(make-variable-buffer-local 'company-search-string)
+
+(defvar company-search-lighter " Search: \"\"")
+(make-variable-buffer-local 'company-search-lighter)
+
+(defvar company-search-old-map nil)
+(make-variable-buffer-local 'company-search-old-map)
+
+(defvar company-search-old-selection 0)
+(make-variable-buffer-local 'company-search-old-selection)
+
+(defun company-search (text lines)
+  (let ((quoted (regexp-quote text))
+        (i 0))
+    (dolist (line lines)
+      (when (string-match quoted line (length company-prefix))
+        (return i))
+      (incf i))))
+
+(defun company-search-printing-char ()
+  (interactive)
+  (setq company-search-string
+        (concat (or company-search-string "") (string last-command-event))
+        company-search-lighter (concat " Search: \"" company-search-string
+                                        "\""))
+  (let ((pos (company-search company-search-string
+                              (nthcdr company-selection company-candidates))))
+    (if (null pos)
+        (ding)
+      (company-set-selection (+ company-selection pos) t))))
+
+(defun company-search-repeat-forward ()
+  (interactive)
+  (let ((pos (company-search company-search-string
+                              (cdr (nthcdr company-selection
+                                           company-candidates)))))
+    (if (null pos)
+        (ding)
+      (company-set-selection (+ company-selection pos 1) t))))
+
+(defun company-search-repeat-backward ()
+  (interactive)
+  (let ((pos (company-search company-search-string
+                              (nthcdr (- (length company-candidates)
+                                         company-selection)
+                                      (reverse company-candidates)))))
+    (if (null pos)
+        (ding)
+      (company-set-selection (- company-selection pos 1) t))))
+
+(defun company-search-abort ()
+  (interactive)
+  (company-set-selection company-search-old-selection t)
+  (company-search-mode 0))
+
+(defun company-search-other-char ()
+  (interactive)
+  (company-search-mode 0)
+  (when last-input-event
+    (clear-this-command-keys t)
+    (setq unread-command-events (list last-input-event))))
+
+(defvar company-search-map
+  (let ((i 0)
+        (keymap (make-keymap)))
+    (set-char-table-range (nth 1 keymap) (cons #x100 (max-char))
+                          'company-search-printing-char)
+    (define-key keymap [t] 'company-search-other-char)
+    (while (< i ?\s)
+      (define-key keymap (make-string 1 i) 'company-search-other-char)
+      (incf i))
+    (while (< i 256)
+      (define-key keymap (vector i) 'company-search-printing-char)
+      (incf i))
+    (let ((meta-map (make-sparse-keymap)))
+      (define-key keymap (char-to-string meta-prefix-char) meta-map)
+      (define-key keymap [escape] meta-map))
+    (define-key keymap (vector meta-prefix-char t) 'company-search-other-char)
+    (define-key keymap "\e\e\e" 'company-search-other-char)
+    (define-key keymap  [escape escape escape] 'company-search-other-char)
+
+    (define-key keymap "\C-g" 'company-search-abort)
+    (define-key keymap "\C-s" 'company-search-repeat-forward)
+    (define-key keymap "\C-r" 'company-search-repeat-backward)
+    keymap))
+
+(define-minor-mode company-search-mode
+  ""
+  nil company-search-lighter nil
+  (if company-search-mode
+      (if (company-manual-begin)
+          (progn
+            (setq company-search-old-selection company-selection)
+            (company-enable-overriding-keymap company-search-map)
+            (company-call-frontends 'update))
+        (setq company-search-mode nil))
+    (kill-local-variable 'company-search-string)
+    (kill-local-variable 'company-search-lighter)
+    (kill-local-variable 'company-search-old-selection)
+    (company-enable-overriding-keymap company-active-map)))
+
+(defun company-search-candidates ()
+  (interactive)
+  (company-search-mode 1))
+
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun company-select-next ()
@@ -532,14 +642,24 @@
 
 (defun company-fill-propertize (line width selected)
   (setq line (company-safe-substring line 0 width))
-  (add-text-properties 0 width
-                       (list 'face (if selected
-                                       'company-tooltip-selection
-                                     'company-tooltip)) line)
+  (add-text-properties 0 width (list 'face 'company-tooltip) line)
   (add-text-properties 0 (length company-common)
-                       (list 'face (if selected
-                                       'company-tooltip-common-selection
-                                     'company-tooltip-common)) line)
+                       (list 'face 'company-tooltip-common) line)
+  (when selected
+    (if (and company-search-string
+             (string-match (regexp-quote company-search-string) line
+                           (length company-prefix)))
+        (progn
+          (add-text-properties (match-beginning 0) (match-end 0)
+                               '(face company-tooltip-selection) line)
+          (when (< (match-beginning 0) (length company-common))
+            (add-text-properties (match-beginning 0) (length company-common)
+                                 '(face company-tooltip-common-selection)
+                                 line)))
+      (add-text-properties 0 width '(face company-tooltip-selection) line)
+      (add-text-properties 0 (length company-common)
+                           (list 'face 'company-tooltip-common-selection)
+                           line)))
   line)
 
 ;;; replace

commit afec57f8273c98b4fd78e4f7e612949f74ab5375
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 17:00:19 2009 +0100

    Don't start in read-only buffers, or when something else is going on.

diff --git a/company.el b/company.el
index 54feaf8..4fd1b9f 100644
--- a/company.el
+++ b/company.el
@@ -341,22 +341,25 @@
         (setq company-candidates nil)))))
 
 (defun company-begin ()
-  (company-continue)
-  (unless company-candidates
-    (let (prefix)
-      (dolist (backend company-backends)
-        (unless (fboundp backend)
-          (ignore-errors (require backend nil t)))
-        (if (fboundp backend)
-            (when (setq prefix (funcall backend 'prefix))
-              (when (company-should-complete prefix)
-                (setq company-backend backend)
-                (company-calculate-candidates prefix))
-              (return prefix))
-          (unless (memq backend company-disabled-backends)
-            (push backend company-disabled-backends)
-            (message "Company back-end '%s' could not be initialized"
-                     backend))))))
+  (if (or buffer-read-only overriding-terminal-local-map overriding-local-map)
+      ;; Don't complete in these cases.
+      (setq company-candidates nil)
+    (company-continue)
+    (unless company-candidates
+      (let (prefix)
+        (dolist (backend company-backends)
+          (unless (fboundp backend)
+            (ignore-errors (require backend nil t)))
+          (if (fboundp backend)
+              (when (setq prefix (funcall backend 'prefix))
+                (when (company-should-complete prefix)
+                  (setq company-backend backend)
+                  (company-calculate-candidates prefix))
+                (return prefix))
+            (unless (memq backend company-disabled-backends)
+              (push backend company-disabled-backends)
+              (message "Company back-end '%s' could not be initialized"
+                       backend)))))))
   (if company-candidates
       (progn
         (setq company-point (point))

commit f027dc51b832e0249326bab4258bf70ea28e8805
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 16:54:10 2009 +0100

    Limit tooltip height to remaining window height.

diff --git a/company.el b/company.el
index 56a5720..54feaf8 100644
--- a/company.el
+++ b/company.el
@@ -570,10 +570,9 @@
             (mapconcat 'identity (nreverse new) "\n")
             "\n")))
 
-(defun company-create-lines (column lines selection)
+(defun company-create-lines (column lines selection limit)
 
-  (let ((limit (max company-tooltip-limit 3))
-        (len (length lines))
+  (let ((len (length lines))
         width
         lines-copy
         previous
@@ -619,6 +618,11 @@
 
 ;; show
 
+(defsubst company-pseudo-tooltip-height ()
+  "Calculate the appropriate tooltip height."
+  (max 3 (min company-tooltip-limit
+              (- (window-height) (cdr (posn-col-row (posn-at-point))) 2))))
+
 (defun company-pseudo-tooltip-show (row column lines selection)
   (company-pseudo-tooltip-hide)
   (unless lines (error "No text provided"))
@@ -626,12 +630,12 @@
 
     (move-to-column 0)
 
-    (let* ((lines (company-create-lines column lines selection))
+    (let* ((height (company-pseudo-tooltip-height))
+           (lines (company-create-lines column lines selection height))
            (nl (< (move-to-window-line row) row))
            (beg (point))
            (end (save-excursion
-                  (move-to-window-line (min (window-height)
-                                            (+ row company-tooltip-limit)))
+                  (move-to-window-line (+ row height))
                   (point)))
            (old-string (company-buffer-lines beg end))
            str)
@@ -643,6 +647,7 @@
       (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
       (overlay-put company-pseudo-tooltip-overlay 'company-before
                    (company-replacement-string old-string lines column nl))
+      (overlay-put company-pseudo-tooltip-overlay 'company-height height)
 
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
@@ -655,7 +660,8 @@
   (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
          (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
          (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
-         (lines (company-create-lines column lines selection)))
+         (height (overlay-get company-pseudo-tooltip-overlay 'company-height))
+         (lines (company-create-lines column lines selection height)))
     (overlay-put company-pseudo-tooltip-overlay 'company-before
                  (company-replacement-string old-string lines column nl))))
 
@@ -679,7 +685,11 @@
   (case command
     ('pre-command (company-pseudo-tooltip-hide-temporarily))
     ('post-command
-     (unless (overlayp company-pseudo-tooltip-overlay)
+     (unless (and (overlayp company-pseudo-tooltip-overlay)
+                  (equal (overlay-get company-pseudo-tooltip-overlay
+                                      'company-height)
+                         (company-pseudo-tooltip-height)))
+       ;; Redraw needed.
        (company-pseudo-tooltip-show-at-point (- (point)
                                                 (length company-prefix))))
      (company-pseudo-tooltip-unhide))

commit 9552b5dc6d44ec5c2ac19f887ec609ddb18e5947
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 16:29:54 2009 +0100

    Recenter window when showing documentation buffer.

diff --git a/company.el b/company.el
index 98b9dcd..56a5720 100644
--- a/company.el
+++ b/company.el
@@ -481,11 +481,16 @@
   (interactive)
   (when company-candidates
     (save-window-excursion
-      (let* ((selected (nth company-selection company-candidates))
+      (let* ((height (window-height))
+             (row (cdr (posn-col-row (posn-at-point))))
+             (selected (nth company-selection company-candidates))
              (buffer (funcall company-backend 'doc-buffer selected)))
         (if (not buffer)
             (error "No documentation available.")
           (display-buffer buffer)
+          (and (< (window-height) height)
+               (< (- (window-height) row 2) company-tooltip-limit)
+               (recenter (- (window-height) row 2)))
           (read-event)
           (when last-input-event
             (clear-this-command-keys t)

commit 887c3363dc4f1ffb8cff5405bb9a9f5122aed1ff
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 14:25:27 2009 +0100

    Fixed accidental "...".

diff --git a/company-elisp.el b/company-elisp.el
index 231446b..5ec3b0a 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -48,7 +48,8 @@
               (ignore-errors
                 (dotimes (i company-elisp-parse-limit)
                   (save-excursion
-                    (down-list 1)
+                    (when (looking-at "[ \t\n]*(")
+                      (down-list 1))
                     (if (looking-at "[ \t\n]*\\(\\(?:\\sw\\|\\s_\\)+\\)")
                         (add-to-list 'vars (match-string-no-properties 1))
                       (error)))
diff --git a/company.el b/company.el
index 92e357a..98b9dcd 100644
--- a/company.el
+++ b/company.el
@@ -513,7 +513,10 @@
   (when (>= company-tooltip-offset (- num-lines limit 1))
     (incf limit)
     (when (= selection (1- num-lines))
-      (setq company-tooltip-offset (max (1- company-tooltip-offset) 0))))
+      (decf company-tooltip-offset)
+      (when (<= company-tooltip-offset 1)
+        (setq company-tooltip-offset 0)
+        (incf limit))))
 
   limit)
 

commit f0bd18e11efef2c9a7fb07cb43e761338ae5be84
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 12:48:28 2009 +0100

    Extracted company-set-selection macro.

diff --git a/company.el b/company.el
index f9cae14..92e357a 100644
--- a/company.el
+++ b/company.el
@@ -281,6 +281,13 @@
   (dolist (frontend company-frontends)
     (funcall frontend command)))
 
+(defsubst company-set-selection (selection)
+  (setq selection (max 0 (min (1- (length company-candidates)) selection)))
+  (unless (equal selection company-selection)
+    (setq company-selection selection
+          company-selection-changed t)
+    (company-call-frontends 'update)))
+
 (defsubst company-calculate-candidates (prefix)
   (or (setq company-candidates (cdr (assoc prefix company-candidates-cache)))
       (let ((len (length prefix))
@@ -402,17 +409,12 @@
 (defun company-select-next ()
   (interactive)
   (when (company-manual-begin)
-    (setq company-selection (min (1- (length company-candidates))
-                                 (1+ company-selection))
-          company-selection-changed t))
-  (company-call-frontends 'update))
+    (company-set-selection (1+ company-selection))))
 
 (defun company-select-previous ()
   (interactive)
   (when (company-manual-begin)
-    (setq company-selection (max 0 (1- company-selection))
-          company-selection-changed t))
-  (company-call-frontends 'update))
+    (company-set-selection (1- company-selection))))
 
 (defun company-complete-selection ()
   (interactive)

commit ae38bd482e93a7ee68a76f20831b7cf8b7fa61fd
Author: Nikolaj Schumacher <address@hidden>
Date:   Mon Mar 16 02:34:06 2009 +0100

    Use overriding active map.

diff --git a/company.el b/company.el
index 627574b..f9cae14 100644
--- a/company.el
+++ b/company.el
@@ -161,13 +161,10 @@
 
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-current-map (make-sparse-keymap))
-
 (defvar company-mode-map (make-sparse-keymap))
 
 (defvar company-active-map
   (let ((keymap (make-sparse-keymap)))
-    (set-keymap-parent keymap company-mode-map)
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap "\C-m" 'company-complete-selection)
@@ -178,11 +175,9 @@
 ;;;###autoload
 (define-minor-mode company-mode
   ""
-  nil " comp" nil
+  nil " comp" company-mode-map
   (if company-mode
       (progn
-        (add-to-list 'minor-mode-overriding-map-alist
-                     (cons 'company-mode company-current-map))
         (add-hook 'pre-command-hook 'company-pre-command nil t)
         (add-hook 'post-command-hook 'company-post-command nil t)
         (company-timer-set 'company-idle-delay
@@ -192,6 +187,46 @@
     (company-cancel)
     (kill-local-variable 'company-point)))
 
+;;; keymaps 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-overriding-keymap-bound nil)
+(make-variable-buffer-local 'company-overriding-keymap-bound)
+
+(defvar company-old-keymap nil)
+(make-variable-buffer-local 'company-old-keymap)
+
+(defvar company-my-keymap nil)
+(make-variable-buffer-local 'company-my-keymap)
+
+(defsubst company-enable-overriding-keymap (keymap)
+  (setq company-my-keymap keymap)
+  (when company-overriding-keymap-bound
+    (company-uninstall-map)))
+
+(defun company-install-map ()
+  (unless (or company-overriding-keymap-bound
+              (null company-my-keymap))
+    (setq company-old-keymap overriding-terminal-local-map
+          overriding-terminal-local-map company-my-keymap
+          company-overriding-keymap-bound t)))
+
+(defun company-uninstall-map ()
+  (when (and company-overriding-keymap-bound
+             (eq overriding-terminal-local-map company-my-keymap))
+    (setq overriding-terminal-local-map company-old-keymap
+          company-overriding-keymap-bound nil)))
+
+;; Hack:
+;; Emacs calculates the active keymaps before reading the event.  That means we
+;; cannot change the keymap from a timer.  So we send a bogus command.
+(defun company-ignore ()
+  (interactive))
+
+(global-set-key '[31415926] 'company-ignore)
+
+(defun company-input-noop ()
+  (push 31415926 unread-command-events))
+
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun company-grab (regexp &optional expression)
@@ -276,7 +311,9 @@
        (not (equal (point) company-point))
        (let ((company-idle-delay t))
          (company-begin)
-         (company-post-command))))
+         (when company-candidates
+           (company-input-noop)
+           (company-post-command)))))
 
 (defun company-manual-begin ()
   (and company-mode
@@ -316,7 +353,7 @@
   (if company-candidates
       (progn
         (setq company-point (point))
-        (set-keymap-parent company-current-map company-active-map)
+        (company-enable-overriding-keymap company-active-map)
         (company-call-frontends 'update))
     (company-cancel)))
 
@@ -330,7 +367,7 @@
         company-selection-changed nil
         company-point nil)
   (company-call-frontends 'hide)
-  (set-keymap-parent company-current-map company-mode-map))
+  (company-enable-overriding-keymap nil))
 
 (defun company-abort ()
   (company-cancel)
@@ -344,7 +381,8 @@
           (company-call-frontends 'pre-command))
       (error (message "Company: An error occurred in pre-command")
              (message "%s" (error-message-string err))
-             (company-cancel)))))
+             (company-cancel))))
+  (company-uninstall-map))
 
 (defun company-post-command ()
   (unless (eq this-command 'company-show-doc-buffer)
@@ -356,7 +394,8 @@
             (company-call-frontends 'post-command)))
       (error (message "Company: An error occurred in post-command")
              (message "%s" (error-message-string err))
-             (company-cancel)))))
+             (company-cancel))))
+  (company-install-map))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 9b2b5b6c623579057e9322bd44a7342d0b08ee92
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 23:26:07 2009 +0100

    Prevented last character in buffer from disappearing.

diff --git a/company.el b/company.el
index e3867b8..627574b 100644
--- a/company.el
+++ b/company.el
@@ -496,10 +496,12 @@
   (goto-char beg)
   (let ((row (cdr (posn-col-row (posn-at-point))))
         lines)
-    (while (< (point) end)
-      (move-to-window-line (incf row))
+    (while (and (equal (move-to-window-line (incf row)) row)
+                (<= (point) end))
       (push (buffer-substring beg (min end (1- (point)))) lines)
       (setq beg (point)))
+    (unless (eq beg end)
+      (push (buffer-substring beg end) lines))
     (nreverse lines)))
 
 (defun company-modify-line (old new offset)

commit ddc54a061616e806e49661d6f863f041eb1dffc8
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 22:28:48 2009 +0100

    Added special keymap that is activated on demand.

diff --git a/company-elisp.el b/company-elisp.el
index df7e568..231446b 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -60,8 +60,9 @@
          (doc (if (fboundp symbol)
                   (documentation symbol t)
                 (documentation-property symbol 'variable-documentation t))))
-    (when (string-match ".*$" doc)
-      (match-string 0 doc))))
+    (and (stringp doc)
+         (string-match ".*$" doc)
+         (match-string 0 doc))))
 
 (defun company-elisp (command &optional arg &rest ignored)
   (case command
diff --git a/company.el b/company.el
index e479fa4..e3867b8 100644
--- a/company.el
+++ b/company.el
@@ -161,21 +161,28 @@
 
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar company-mode-map
+(defvar company-current-map (make-sparse-keymap))
+
+(defvar company-mode-map (make-sparse-keymap))
+
+(defvar company-active-map
   (let ((keymap (make-sparse-keymap)))
+    (set-keymap-parent keymap company-mode-map)
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
-    (define-key keymap (kbd "M-<return>") 'company-complete-selection)
-    (define-key keymap "\t" 'company-complete)
+    (define-key keymap "\C-m" 'company-complete-selection)
+    (define-key keymap "\t" 'company-complete-common)
     (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     keymap))
 
 ;;;###autoload
 (define-minor-mode company-mode
   ""
-  nil " comp" company-mode-map
+  nil " comp" nil
   (if company-mode
       (progn
+        (add-to-list 'minor-mode-overriding-map-alist
+                     (cons 'company-mode company-current-map))
         (add-hook 'pre-command-hook 'company-pre-command nil t)
         (add-hook 'post-command-hook 'company-post-command nil t)
         (company-timer-set 'company-idle-delay
@@ -309,6 +316,7 @@
   (if company-candidates
       (progn
         (setq company-point (point))
+        (set-keymap-parent company-current-map company-active-map)
         (company-call-frontends 'update))
     (company-cancel)))
 
@@ -321,7 +329,8 @@
         company-selection 0
         company-selection-changed nil
         company-point nil)
-  (company-call-frontends 'hide))
+  (company-call-frontends 'hide)
+  (set-keymap-parent company-current-map company-mode-map))
 
 (defun company-abort ()
   (company-cancel)

commit 7cb38f2a04e068fe36002148f3b1963f906decf4
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 21:32:22 2009 +0100

    Added back-end file headers.

diff --git a/company-css.el b/company-css.el
index af513ca..44ec09f 100644
--- a/company-css.el
+++ b/company-css.el
@@ -1,3 +1,22 @@
+;;; company-css.el --- a company-mode completion back-end for css-mode
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (eval-when-compile (require 'cl))
 
diff --git a/company-dabbrev.el b/company-dabbrev.el
index 0571260..ecd8610 100644
--- a/company-dabbrev.el
+++ b/company-dabbrev.el
@@ -1,3 +1,22 @@
+;;; company-dabbrev.el --- a company-mode completion back-end for dabbrev
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (require 'dabbrev)
 (eval-when-compile (require 'cl))
diff --git a/company-elisp.el b/company-elisp.el
index 6373aea..df7e568 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -1,3 +1,22 @@
+;;; company-elisp.el --- a company-mode completion back-end for emacs-lisp-mode
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (eval-when-compile (require 'cl))
 
diff --git a/company-ispell.el b/company-ispell.el
index a581170..b5b1a61 100644
--- a/company-ispell.el
+++ b/company-ispell.el
@@ -1,3 +1,22 @@
+;;; company-ispell.el --- a company-mode completion back-end using ispell
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (require 'ispell)
 (eval-when-compile (require 'cl))
diff --git a/company-nxml.el b/company-nxml.el
index 18badc8..72cb234 100644
--- a/company-nxml.el
+++ b/company-nxml.el
@@ -1,3 +1,22 @@
+;;; company-nxml.el --- a company-mode completion back-end for nxml-mode
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (require 'nxml-mode)
 (require 'rng-nxml)
diff --git a/company-oddmuse.el b/company-oddmuse.el
index cf41e7b..d9602dd 100644
--- a/company-oddmuse.el
+++ b/company-oddmuse.el
@@ -1,3 +1,22 @@
+;;; company-oddmuse.el --- a company-mode completion back-end for oddmuse-mode
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (require 'oddmuse)
 (eval-when-compile (require 'cl))
diff --git a/company-semantic.el b/company-semantic.el
index 960e69b..a310927 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -1,3 +1,22 @@
+;;; company-semantic.el --- a company-mode back-end using CEDET Semantic
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; This file is part of company.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 (require 'company)
 (require 'semantic-ia)
 (eval-when-compile (require 'cl))
diff --git a/company.el b/company.el
index a43fcba..e479fa4 100644
--- a/company.el
+++ b/company.el
@@ -1,3 +1,36 @@
+;;; company.el --- extensible inline text completion mechanism
+;;
+;; Copyright (C) 2009 Nikolaj Schumacher
+;;
+;; Author: Nikolaj Schumacher <bugs * nschum de>
+;; Version: 
+;; Keywords: abbrev, convenience, matchis
+;; URL: http://nschum.de/src/emacs/company/
+;; Compatibility: GNU Emacs 23.x
+;;
+;; This file is NOT part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License
+;; as published by the Free Software Foundation; either version 2
+;; of the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;;; Commentary:
+;;
+;;; Change Log:
+;;
+;;    Initial release.
+;;
+;;; Code:
+
 (eval-when-compile (require 'cl))
 
 (add-to-list 'debug-ignored-errors

commit d4dbefa465df2b92c31b666d881f0eb01d9ec9ec
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 20:09:51 2009 +0100

    Added dabbrev back-end.

diff --git a/company-dabbrev.el b/company-dabbrev.el
new file mode 100644
index 0000000..0571260
--- /dev/null
+++ b/company-dabbrev.el
@@ -0,0 +1,22 @@
+(require 'company)
+(require 'dabbrev)
+(eval-when-compile (require 'cl))
+
+(defun company-grab-dabbrev-prefix ()
+  (save-excursion
+    (when (looking-at "\\>")
+      (let ((end (point)))
+        (dabbrev--reset-global-variables)
+        (dabbrev--goto-start-of-abbrev)
+        (buffer-substring-no-properties (point) end)))))
+
+(defun company-dabbrev (command &optional arg &rest ignored)
+  (case command
+    ('prefix (company-grab-dabbrev-prefix))
+    ('candidates (let ((dabbrev-check-other-buffers))
+                   (dabbrev--reset-global-variables)
+                   (dabbrev--find-all-expansions arg t)))
+    ('ignore-case t)))
+
+(provide 'company-dabbrev)
+;;; company-dabbrev.el ends here
diff --git a/company.el b/company.el
index 41cc343..a43fcba 100644
--- a/company.el
+++ b/company.el
@@ -99,7 +99,8 @@
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-oddmuse company-ispell)
+                              company-semantic company-oddmuse
+                              company-dabbrev)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))

commit c67087a80dbfc64fb67b0dc79291a3a9781ff02e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 19:50:17 2009 +0100

    Protect against errors.

diff --git a/company.el b/company.el
index c15f151..41cc343 100644
--- a/company.el
+++ b/company.el
@@ -296,15 +296,24 @@
 
 (defun company-pre-command ()
   (unless (eq this-command 'company-show-doc-buffer)
-    (when company-candidates
-      (company-call-frontends 'pre-command))))
+    (condition-case err
+        (when company-candidates
+          (company-call-frontends 'pre-command))
+      (error (message "Company: An error occurred in pre-command")
+             (message "%s" (error-message-string err))
+             (company-cancel)))))
 
 (defun company-post-command ()
   (unless (eq this-command 'company-show-doc-buffer)
-    (unless (equal (point) company-point)
-      (company-begin))
-    (when company-candidates
-      (company-call-frontends 'post-command))))
+    (condition-case err
+        (progn
+          (unless (equal (point) company-point)
+            (company-begin))
+          (when company-candidates
+            (company-call-frontends 'post-command)))
+      (error (message "Company: An error occurred in post-command")
+             (message "%s" (error-message-string err))
+             (company-cancel)))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit 5bd0920a899e520ecedc281a6c1324819dfffb71
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 19:37:11 2009 +0100

    Added documentation buffer.

diff --git a/company-elisp.el b/company-elisp.el
index 37cf7ac..6373aea 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -52,7 +52,9 @@
                    (append (all-completions arg (company-elisp-parse-let))
                            (all-completions arg obarray
                                             'company-elisp-predicate))))
-    ('meta (company-elisp-doc arg))))
+    ('meta (company-elisp-doc arg))
+    ('doc-buffer (describe-function 'describe-function)
+                 (help-buffer))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company-semantic.el b/company-semantic.el
index 8fba9cf..960e69b 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -27,6 +27,15 @@
                     "\n"))
             doc)))
 
+(defun company-semantic-doc-buffer (tag)
+  (let ((doc (semantic-documentation-for-tag tag)))
+    (when doc
+      (with-current-buffer (company-doc-buffer)
+        (insert (funcall semantic-idle-summary-function tag nil t)
+                "\n"
+                doc)
+        (current-buffer)))))
+
 (defsubst company-semantic-completions (prefix)
   (ignore-errors
     (let ((completion-ignore-case nil)
@@ -42,7 +51,9 @@
                      (mapcar 'semantic-tag-name
                              (semantic-analyze-find-tags-by-prefix arg))))
     ('meta (funcall company-semantic-metadata-function
-                    (semantic-analyze-find-tag arg)))))
+                    (semantic-analyze-find-tag arg)))
+    ('doc-buffer (company-semantic-doc-buffer (semantic-analyze-find-tag arg)))
+    ))
 
 (provide 'company-semantic)
 ;;; company-semantic.el ends here
diff --git a/company.el b/company.el
index c65bd06..c15f151 100644
--- a/company.el
+++ b/company.el
@@ -4,6 +4,7 @@
              "^Pseudo tooltip frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
+(add-to-list 'debug-ignored-errors "^No documentation available$")
 
 (defgroup company nil
   ""
@@ -132,6 +133,7 @@
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap (kbd "M-<return>") 'company-complete-selection)
     (define-key keymap "\t" 'company-complete)
+    (define-key keymap (kbd "<f1>") 'company-show-doc-buffer)
     keymap))
 
 ;;;###autoload
@@ -293,14 +295,16 @@
   (setq company-point (point)))
 
 (defun company-pre-command ()
-  (when company-candidates
-    (company-call-frontends 'pre-command)))
+  (unless (eq this-command 'company-show-doc-buffer)
+    (when company-candidates
+      (company-call-frontends 'pre-command))))
 
 (defun company-post-command ()
-  (unless (equal (point) company-point)
-    (company-begin))
-  (when company-candidates
-    (company-call-frontends 'post-command)))
+  (unless (eq this-command 'company-show-doc-buffer)
+    (unless (equal (point) company-point)
+      (company-begin))
+    (when company-candidates
+      (company-call-frontends 'post-command))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -375,6 +379,25 @@
             (cons selected (funcall company-backend 'meta selected))))
     (cdr company-last-metadata)))
 
+(defun company-doc-buffer (&optional string)
+  (with-current-buffer (get-buffer-create "*Company meta-data*")
+    (erase-buffer)
+    (current-buffer)))
+
+(defun company-show-doc-buffer ()
+  (interactive)
+  (when company-candidates
+    (save-window-excursion
+      (let* ((selected (nth company-selection company-candidates))
+             (buffer (funcall company-backend 'doc-buffer selected)))
+        (if (not buffer)
+            (error "No documentation available.")
+          (display-buffer buffer)
+          (read-event)
+          (when last-input-event
+            (clear-this-command-keys t)
+            (setq unread-command-events (list last-input-event))))))))
+
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-pseudo-tooltip-overlay nil)

commit 3c27815a3c237e318f9ae42a1c9c5c74158ebb59
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 18:16:40 2009 +0100

    Added doc-line front-end.

diff --git a/company-elisp.el b/company-elisp.el
index 481a55b..37cf7ac 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -36,6 +36,14 @@
                   (forward-sexp))))))))
     vars))
 
+(defun company-elisp-doc (symbol)
+  (let* ((symbol (intern symbol))
+         (doc (if (fboundp symbol)
+                  (documentation symbol t)
+                (documentation-property symbol 'variable-documentation t))))
+    (when (string-match ".*$" doc)
+      (match-string 0 doc))))
+
 (defun company-elisp (command &optional arg &rest ignored)
   (case command
     ('prefix (and (eq major-mode 'emacs-lisp-mode)
@@ -43,7 +51,8 @@
     ('candidates (let ((completion-ignore-case nil))
                    (append (all-completions arg (company-elisp-parse-let))
                            (all-completions arg obarray
-                                            'company-elisp-predicate))))))
+                                            'company-elisp-predicate))))
+    ('meta (company-elisp-doc arg))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here
diff --git a/company-semantic.el b/company-semantic.el
index 0b4906c..8fba9cf 100644
--- a/company-semantic.el
+++ b/company-semantic.el
@@ -2,9 +2,31 @@
 (require 'semantic-ia)
 (eval-when-compile (require 'cl))
 
+(defcustom company-semantic-metadata-function 'company-semantic-summary-and-doc
+  "*"
+  :group 'company
+  :type 'function)
+
 (defvar company-semantic-context-regexp
   "\\(->\\|\\.\\|\\_<\\)\\(\\(\\s_\\|\\sw\\)+\\_>\\=\\)")
 
+(defun company-semantic-doc-or-summary (tag)
+  (or (semantic-documentation-for-tag tag)
+      (funcall semantic-idle-summary-function tag nil t)))
+
+(defun company-semantic-summary-and-doc (tag)
+  (let ((doc (semantic-documentation-for-tag tag))
+        (summary (funcall semantic-idle-summary-function tag nil t)))
+    (and (stringp doc)
+         (string-match "\n*\\(.*\\)$" doc)
+         (setq doc (match-string 1 doc)))
+    (concat (funcall semantic-idle-summary-function tag nil t)
+            (when doc
+                  (if (< (+ (length doc) (length summary) 4) (window-width))
+                      " -- "
+                    "\n"))
+            doc)))
+
 (defsubst company-semantic-completions (prefix)
   (ignore-errors
     (let ((completion-ignore-case nil)
@@ -18,7 +40,9 @@
                   (or (company-grab company-semantic-context-regexp 2) "")))
     ('candidates (or (company-semantic-completions arg)
                      (mapcar 'semantic-tag-name
-                             (semantic-analyze-find-tags-by-prefix arg))))))
+                             (semantic-analyze-find-tags-by-prefix arg))))
+    ('meta (funcall company-semantic-metadata-function
+                    (semantic-analyze-find-tag arg)))))
 
 (provide 'company-semantic)
 ;;; company-semantic.el ends here
diff --git a/company.el b/company.el
index 73f4751..c65bd06 100644
--- a/company.el
+++ b/company.el
@@ -3,6 +3,7 @@
 (add-to-list 'debug-ignored-errors
              "^Pseudo tooltip frontend cannot be used twice$")
 (add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
+(add-to-list 'debug-ignored-errors "^Echo area cannot be used twice$")
 
 (defgroup company nil
   ""
@@ -71,15 +72,18 @@
   (and (memq 'company-preview-if-just-one-frontend value)
        (memq 'company-preview-frontend value)
        (error "Preview frontend cannot be used twice"))
+  (and (memq 'company-echo value)
+       (memq 'company-echo-metadata-frontend value)
+       (error "Echo area cannot be used twice"))
   ;; preview must come last
   (dolist (f '(company-preview-if-just-one-frontend company-preview-frontend))
     (when (memq f value)
       (setq value (append (delq f value) (list f)))))
   (set variable value))
 
-(defcustom company-frontends '(company-echo-frontend
-                               company-pseudo-tooltip-unless-just-one-frontend
-                               company-preview-if-just-one-frontend)
+(defcustom company-frontends '(company-pseudo-tooltip-unless-just-one-frontend
+                               company-preview-if-just-one-frontend
+                               company-echo-metadata-frontend)
   "*"
   :set 'company-frontends-set
   :group 'company
@@ -359,6 +363,18 @@
                   (company-space-string (- to len)))
         (substring str from to)))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-last-metadata nil)
+(make-variable-buffer-local 'company-last-metadata)
+
+(defun company-fetch-metadata ()
+  (let ((selected (nth company-selection company-candidates)))
+    (unless (equal selected (car company-last-metadata))
+      (setq company-last-metadata
+            (cons selected (funcall company-backend 'meta selected))))
+    (cdr company-last-metadata)))
+
 ;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-pseudo-tooltip-overlay nil)
@@ -629,5 +645,13 @@
     ('post-command (company-echo-show company-candidates))
     ('hide (setq company-echo-last-msg nil))))
 
+(defun company-echo-metadata-frontend (command)
+  (case command
+    ('pre-command (company-echo-refresh))
+    ('post-command (setq company-echo-last-msg (company-fetch-metadata))
+                   (company-echo-refresh))
+    ('hide (setq company-echo-last-msg nil))))
+
+
 (provide 'company)
 ;;; company.el ends here

commit 73493037c62ff899ac70024ea868d80426a26102
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 17:02:19 2009 +0100

    Added OddMuse back-end.

diff --git a/company-oddmuse.el b/company-oddmuse.el
new file mode 100644
index 0000000..cf41e7b
--- /dev/null
+++ b/company-oddmuse.el
@@ -0,0 +1,20 @@
+(require 'company)
+(require 'oddmuse)
+(eval-when-compile (require 'cl))
+
+(defvar company-oddmuse-link-regexp
+  "\\(\\<[A-Z][[:alnum:]]*\\>\\)\\|\\[\\[\\([[:alnum:]]+\\>\\|\\)")
+
+(defun company-oddmuse (command &optional arg &rest ignored)
+  (case command
+    ('prefix (let ((case-fold-search nil))
+               (and (eq major-mode 'oddmuse-mode)
+                    (looking-back company-oddmuse-link-regexp (point-at-bol))
+                    (or (match-string 1)
+                        (match-string 2)))))
+    ('candidates (all-completions arg
+                                  (oddmuse-make-completion-table 
oddmuse-wiki)))
+    ))
+
+(provide 'company-oddmuse)
+;;; company-oddmuse.el ends here
diff --git a/company.el b/company.el
index b2a4582..73f4751 100644
--- a/company.el
+++ b/company.el
@@ -94,7 +94,7 @@
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-semantic company-ispell)
+                              company-semantic company-oddmuse company-ispell)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))

commit 825d8ed76aa511cbfa75bdb0c8cca6bb2ec387e8
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 16:51:23 2009 +0100

    Added semantic backend.

diff --git a/company-semantic.el b/company-semantic.el
new file mode 100644
index 0000000..0b4906c
--- /dev/null
+++ b/company-semantic.el
@@ -0,0 +1,24 @@
+(require 'company)
+(require 'semantic-ia)
+(eval-when-compile (require 'cl))
+
+(defvar company-semantic-context-regexp
+  "\\(->\\|\\.\\|\\_<\\)\\(\\(\\s_\\|\\sw\\)+\\_>\\=\\)")
+
+(defsubst company-semantic-completions (prefix)
+  (ignore-errors
+    (let ((completion-ignore-case nil)
+          (context (semantic-analyze-current-context)))
+      (all-completions prefix (semantic-ia-get-completions context (point))))))
+
+(defun company-semantic (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (memq major-mode '(c-mode c++-mode jde-mode java-mode))
+                  (not (company-in-string-or-comment))
+                  (or (company-grab company-semantic-context-regexp 2) "")))
+    ('candidates (or (company-semantic-completions arg)
+                     (mapcar 'semantic-tag-name
+                             (semantic-analyze-find-tags-by-prefix arg))))))
+
+(provide 'company-semantic)
+;;; company-semantic.el ends here
diff --git a/company.el b/company.el
index 4a67cb5..b2a4582 100644
--- a/company.el
+++ b/company.el
@@ -94,7 +94,7 @@
                          (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp company-nxml company-css
-                              company-ispell)
+                              company-semantic company-ispell)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))

commit 94f6a1917ba71f7beafa5e1164b6becebc0149e2
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 15:05:49 2009 +0100

    Added completion for local lisp variables.

diff --git a/company-elisp.el b/company-elisp.el
index b915423..481a55b 100644
--- a/company-elisp.el
+++ b/company-elisp.el
@@ -10,14 +10,40 @@
                  (/= (char-before (- (point) (length prefix))) ?`))
       prefix)))
 
+(defun company-elisp-predicate (symbol)
+  (or (boundp symbol)
+      (fboundp symbol)))
+
+(defvar company-elisp-parse-limit 30)
+(defvar company-elisp-parse-depth 100)
+
+(defun company-elisp-parse-let ()
+  (let (vars)
+    (ignore-errors
+      (save-excursion
+        (dotimes (i company-elisp-parse-depth)
+          (up-list -1)
+          (save-excursion
+            (when (looking-at "([ \t\n]*let")
+              (down-list 2)
+              (ignore-errors
+                (dotimes (i company-elisp-parse-limit)
+                  (save-excursion
+                    (down-list 1)
+                    (if (looking-at "[ \t\n]*\\(\\(?:\\sw\\|\\s_\\)+\\)")
+                        (add-to-list 'vars (match-string-no-properties 1))
+                      (error)))
+                  (forward-sexp))))))))
+    vars))
+
 (defun company-elisp (command &optional arg &rest ignored)
   (case command
     ('prefix (and (eq major-mode 'emacs-lisp-mode)
                   (company-grab-lisp-symbol)))
     ('candidates (let ((completion-ignore-case nil))
-                   (all-completions arg obarray
-                                    (lambda (symbol) (or (boundp symbol)
-                                                         (fboundp 
symbol))))))))
+                   (append (all-completions arg (company-elisp-parse-let))
+                           (all-completions arg obarray
+                                            'company-elisp-predicate))))))
 
 (provide 'company-elisp)
 ;;; company-elisp.el ends here

commit 94eadf9dd6fa51060078fd9142693f5612b5ac6d
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 12:37:22 2009 +0100

    Redraw pseudo-tooltip less frequently.

diff --git a/company.el b/company.el
index 02c5337..4a67cb5 100644
--- a/company.el
+++ b/company.el
@@ -305,13 +305,15 @@
   (when (company-manual-begin)
     (setq company-selection (min (1- (length company-candidates))
                                  (1+ company-selection))
-          company-selection-changed t)))
+          company-selection-changed t))
+  (company-call-frontends 'update))
 
 (defun company-select-previous ()
   (interactive)
   (when (company-manual-begin)
     (setq company-selection (max 0 (1- company-selection))
-          company-selection-changed t)))
+          company-selection-changed t))
+  (company-call-frontends 'update))
 
 (defun company-complete-selection ()
   (interactive)
@@ -414,9 +416,8 @@
           new
           (company-safe-substring old (+ offset (length new)))))
 
-(defun company-modified-substring (beg end lines column nl)
-  (let ((old (company-buffer-lines beg end))
-        new)
+(defun company-replacement-string (old lines column nl)
+  (let (new)
     ;; Inject into old lines.
     (while old
       (push (company-modify-line (pop old) (pop lines) column) new))
@@ -427,73 +428,80 @@
             (mapconcat 'identity (nreverse new) "\n")
             "\n")))
 
-;; show
+(defun company-create-lines (column lines selection)
 
-(defun company-pseudo-tooltip-show (row column lines selection)
-  (company-pseudo-tooltip-hide)
-  (unless lines (error "No text provided"))
-  (save-excursion
+  (let ((limit (max company-tooltip-limit 3))
+        (len (length lines))
+        width
+        lines-copy
+        previous
+        remainder
+        new)
 
-    (let ((limit (max company-tooltip-limit 3))
-          (len (length lines))
-          width
-          lines-copy
-          previous
-          remainder
-          new)
+    ;; Scroll to offset.
+    (setq limit (company-pseudo-tooltip-update-offset selection len limit))
 
-      ;; Scroll to offset.
-      (setq limit (company-pseudo-tooltip-update-offset selection len limit))
+    (when (> company-tooltip-offset 0)
+      (setq previous (format "...(%d)" company-tooltip-offset)))
 
-      (when (> company-tooltip-offset 0)
-        (setq previous (format "...(%d)" company-tooltip-offset)))
+    (setq remainder (- len limit company-tooltip-offset)
+          remainder (when (> remainder 0)
+                      (setq remainder (format "...(%d)" remainder))))
 
-      (setq remainder (- len limit company-tooltip-offset)
-            remainder (when (> remainder 0)
-                        (setq remainder (format "...(%d)" remainder))))
+    (decf selection company-tooltip-offset)
+    (setq width (min (length previous) (length remainder))
+          lines (nthcdr company-tooltip-offset lines)
+          len (min limit (length lines))
+          lines-copy lines)
 
-      (decf selection company-tooltip-offset)
-      (setq width (min (length previous) (length remainder))
-            lines (nthcdr company-tooltip-offset lines)
-            len (min limit (length lines))
-            lines-copy lines)
+    (dotimes (i len)
+      (setq width (max (length (pop lines-copy)) width)))
+    (setq width (min width (- (window-width) column)))
 
-      (dotimes (i len)
-        (setq width (max (length (pop lines-copy)) width)))
-      (setq width (min width (- (window-width) column)))
+    (when previous
+      (push (propertize (company-safe-substring previous 0 width)
+                        'face 'company-tooltip)
+            new))
 
-      (when previous
-        (push (propertize (company-safe-substring previous 0 width)
-                          'face 'company-tooltip)
-              new))
+    (dotimes (i len)
+      (push (company-fill-propertize (company-reformat (pop lines))
+                                     width (equal i selection))
+            new))
 
-      (dotimes (i len)
-        (push (company-fill-propertize (company-reformat (pop lines))
-                                       width (equal i selection))
-              new))
+    (when remainder
+      (push (propertize (company-safe-substring remainder 0 width)
+                        'face 'company-tooltip)
+            new))
 
-      (when remainder
-        (push (propertize (company-safe-substring remainder 0 width)
-                          'face 'company-tooltip)
-              new))
+    (setq lines (nreverse new))))
+
+;; show
 
-      (setq lines (nreverse new)))
+(defun company-pseudo-tooltip-show (row column lines selection)
+  (company-pseudo-tooltip-hide)
+  (unless lines (error "No text provided"))
+  (save-excursion
 
     (move-to-column 0)
 
-    (let ((nl (< (move-to-window-line row) row))
-          (beg (point))
-          (end (save-excursion
-                 (move-to-window-line (min (window-height)
-                                           (+ row company-tooltip-limit)))
-                 (point)))
-          str)
+    (let* ((lines (company-create-lines column lines selection))
+           (nl (< (move-to-window-line row) row))
+           (beg (point))
+           (end (save-excursion
+                  (move-to-window-line (min (window-height)
+                                            (+ row company-tooltip-limit)))
+                  (point)))
+           (old-string (company-buffer-lines beg end))
+           str)
 
       (setq company-pseudo-tooltip-overlay (make-overlay beg end))
 
-      (overlay-put company-pseudo-tooltip-overlay 'before-string
-                   (company-modified-substring beg end lines column nl))
-      (overlay-put company-pseudo-tooltip-overlay 'invisible t)
+      (overlay-put company-pseudo-tooltip-overlay 'company-old old-string)
+      (overlay-put company-pseudo-tooltip-overlay 'company-column column)
+      (overlay-put company-pseudo-tooltip-overlay 'company-nl nl)
+      (overlay-put company-pseudo-tooltip-overlay 'company-before
+                   (company-replacement-string old-string lines column nl))
+
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
 (defun company-pseudo-tooltip-show-at-point (pos)
@@ -501,18 +509,43 @@
     (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
                                  company-candidates company-selection)))
 
+(defun company-pseudo-tooltip-edit (lines selection)
+  (let* ((old-string (overlay-get company-pseudo-tooltip-overlay 'company-old))
+         (column (overlay-get company-pseudo-tooltip-overlay 'company-column))
+         (nl (overlay-get company-pseudo-tooltip-overlay 'company-nl))
+         (lines (company-create-lines column lines selection)))
+    (overlay-put company-pseudo-tooltip-overlay 'company-before
+                 (company-replacement-string old-string lines column nl))))
+
 (defun company-pseudo-tooltip-hide ()
   (when company-pseudo-tooltip-overlay
     (delete-overlay company-pseudo-tooltip-overlay)
     (setq company-pseudo-tooltip-overlay nil)))
 
+(defun company-pseudo-tooltip-hide-temporarily ()
+  (when (overlayp company-pseudo-tooltip-overlay)
+    (overlay-put company-pseudo-tooltip-overlay 'invisible nil)
+    (overlay-put company-pseudo-tooltip-overlay 'before-string nil)))
+
+(defun company-pseudo-tooltip-unhide ()
+  (when company-pseudo-tooltip-overlay
+    (overlay-put company-pseudo-tooltip-overlay 'invisible t)
+    (overlay-put company-pseudo-tooltip-overlay 'before-string
+                 (overlay-get company-pseudo-tooltip-overlay 
'company-before))))
+
 (defun company-pseudo-tooltip-frontend (command)
   (case command
-    ('pre-command (company-pseudo-tooltip-hide))
-    ('post-command (company-pseudo-tooltip-show-at-point
-                    (- (point) (length company-prefix))))
+    ('pre-command (company-pseudo-tooltip-hide-temporarily))
+    ('post-command
+     (unless (overlayp company-pseudo-tooltip-overlay)
+       (company-pseudo-tooltip-show-at-point (- (point)
+                                                (length company-prefix))))
+     (company-pseudo-tooltip-unhide))
     ('hide (company-pseudo-tooltip-hide)
-           (setq company-tooltip-offset 0))))
+           (setq company-tooltip-offset 0))
+    ('update (when (overlayp company-pseudo-tooltip-overlay)
+               (company-pseudo-tooltip-edit company-candidates
+                                            company-selection)))))
 
 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
   (unless (and (eq command 'post-command)

commit b6a2ea940cc61079d072f9e2f7b7d8387b5f809d
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 10:55:58 2009 +0100

    Added more complete cache.

diff --git a/company.el b/company.el
index c593591..02c5337 100644
--- a/company.el
+++ b/company.el
@@ -166,6 +166,9 @@
 (defvar company-candidates nil)
 (make-variable-buffer-local 'company-candidates)
 
+(defvar company-candidates-cache nil)
+(make-variable-buffer-local 'company-candidates-cache)
+
 (defvar company-common nil)
 (make-variable-buffer-local 'company-common)
 
@@ -196,6 +199,30 @@
   (dolist (frontend company-frontends)
     (funcall frontend command)))
 
+(defsubst company-calculate-candidates (prefix)
+  (or (setq company-candidates (cdr (assoc prefix company-candidates-cache)))
+      (let ((len (length prefix))
+            (completion-ignore-case (funcall company-backend 'ignore-case))
+            prev)
+        (dotimes (i len)
+          (when (setq prev (cdr (assoc (substring prefix 0 (- len i))
+                                       company-candidates-cache)))
+            (setq company-candidates (all-completions prefix prev))
+            (return t))))
+      (progn
+        (setq company-candidates (funcall company-backend 'candidates prefix))
+        (unless (funcall company-backend 'sorted)
+          (setq company-candidates (sort company-candidates 'string<)))))
+  (unless (assoc prefix company-candidates-cache)
+    (push (cons prefix company-candidates) company-candidates-cache))
+  (setq company-selection 0
+        company-prefix prefix)
+  (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
+    (setq company-common (try-completion company-prefix company-candidates)))
+  (when (eq company-common t)
+    (setq company-candidates nil))
+  company-candidates)
+
 (defun company-idle-begin ()
   (and company-mode
        (not company-candidates)
@@ -213,32 +240,13 @@
   ;; Return non-nil if active.
   company-candidates)
 
-(defun company-continue-add (new-prefix)
-  (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
-    (and (< (length company-prefix) (length new-prefix))
-         (equal (substring new-prefix 0 (length company-prefix)) 
company-prefix)
-         (setq company-candidates
-               (all-completions new-prefix company-candidates))
-         (setq company-prefix new-prefix)
-         (setq company-selection 0))))
-
-(defun company-continue-remove (new-prefix)
-  (and (> (length company-prefix) (length new-prefix))
-       (equal (substring company-prefix 0 (length new-prefix)) new-prefix)
-       (setq company-candidates
-             (funcall company-backend 'candidates new-prefix))
-       (setq company-prefix new-prefix)
-       (setq company-selection 0)))
-
 (defun company-continue ()
   (when company-candidates
     (let ((new-prefix (funcall company-backend 'prefix)))
-      (if (and (= (- (point) (length new-prefix))
-                  (- company-point (length company-prefix)))
-               (or (equal company-prefix new-prefix)
-                   (company-continue-add new-prefix)
-                   (company-continue-remove new-prefix)))
-          (company-call-frontends 'update)
+      (unless (and (= (- (point) (length new-prefix))
+                      (- company-point (length company-prefix)))
+                   (or (equal company-prefix new-prefix)
+                       (company-calculate-candidates new-prefix)))
         (setq company-candidates nil)))))
 
 (defun company-begin ()
@@ -251,32 +259,24 @@
         (if (fboundp backend)
             (when (setq prefix (funcall backend 'prefix))
               (when (company-should-complete prefix)
-                (setq company-backend backend
-                      company-prefix prefix
-                      company-candidates
-                      (funcall company-backend 'candidates prefix)
-                      company-selection 0)
-                (unless (funcall company-backend 'sorted)
-                  (setq company-candidates
-                        (sort company-candidates 'string<)))
-                (company-call-frontends 'update))
+                (setq company-backend backend)
+                (company-calculate-candidates prefix))
               (return prefix))
           (unless (memq backend company-disabled-backends)
             (push backend company-disabled-backends)
             (message "Company back-end '%s' could not be initialized"
                      backend))))))
-  (if (or (not company-candidates)
-          (eq t (let ((completion-ignore-case (funcall company-backend
-                                                       'ignore-case)))
-                  (setq company-common
-                        (try-completion company-prefix company-candidates)))))
-      (company-cancel)
-    (setq company-point (point))))
+  (if company-candidates
+      (progn
+        (setq company-point (point))
+        (company-call-frontends 'update))
+    (company-cancel)))
 
 (defun company-cancel ()
   (setq company-backend nil
         company-prefix nil
         company-candidates nil
+        company-candidates-cache nil
         company-common nil
         company-selection 0
         company-selection-changed nil

commit 3dcfd24c42684c578f2ff806b021c009b45832e6
Author: Nikolaj Schumacher <address@hidden>
Date:   Sun Mar 15 09:54:53 2009 +0100

    Added incremental completion.

diff --git a/company.el b/company.el
index f6a7f51..c593591 100644
--- a/company.el
+++ b/company.el
@@ -213,50 +213,65 @@
   ;; Return non-nil if active.
   company-candidates)
 
-(defun company-continue-or-cancel ()
+(defun company-continue-add (new-prefix)
+  (let ((completion-ignore-case (funcall company-backend 'ignore-case)))
+    (and (< (length company-prefix) (length new-prefix))
+         (equal (substring new-prefix 0 (length company-prefix)) 
company-prefix)
+         (setq company-candidates
+               (all-completions new-prefix company-candidates))
+         (setq company-prefix new-prefix)
+         (setq company-selection 0))))
+
+(defun company-continue-remove (new-prefix)
+  (and (> (length company-prefix) (length new-prefix))
+       (equal (substring company-prefix 0 (length new-prefix)) new-prefix)
+       (setq company-candidates
+             (funcall company-backend 'candidates new-prefix))
+       (setq company-prefix new-prefix)
+       (setq company-selection 0)))
+
+(defun company-continue ()
   (when company-candidates
-    (let ((old-point (- company-point (length company-prefix)))
-          (company-idle-delay t)
-          (company-minimum-prefix-length 0))
-      ;; TODO: Make more efficient.
-      (setq company-candidates nil)
-      (company-begin)
-      (unless (and company-candidates
-                   (equal old-point (- company-point (length company-prefix))))
-        (company-cancel))
-      company-candidates)))
+    (let ((new-prefix (funcall company-backend 'prefix)))
+      (if (and (= (- (point) (length new-prefix))
+                  (- company-point (length company-prefix)))
+               (or (equal company-prefix new-prefix)
+                   (company-continue-add new-prefix)
+                   (company-continue-remove new-prefix)))
+          (company-call-frontends 'update)
+        (setq company-candidates nil)))))
 
 (defun company-begin ()
-  (or (company-continue-or-cancel)
-      (let (prefix)
-        (dolist (backend company-backends)
-          (unless (fboundp backend)
-            (ignore-errors (require backend nil t)))
-          (if (fboundp backend)
-              (when (setq prefix (funcall backend 'prefix))
-                (when (company-should-complete prefix)
-                  (setq company-backend backend
-                        company-prefix prefix
-                        company-candidates
-                        (funcall company-backend 'candidates prefix)
-                        company-common
-                        (let ((completion-ignore-case (funcall backend
-                                                               'ignore-case)))
-                          (try-completion prefix company-candidates))
-                        company-selection 0
-                        company-point (point))
-                  (unless (funcall company-backend 'sorted)
-                    (setq company-candidates
-                          (sort company-candidates 'string<)))
-                  (company-call-frontends 'update))
-                (return prefix))
-            (unless (memq backend company-disabled-backends)
-              (push backend company-disabled-backends)
-              (message "Company back-end '%s' could not be initialized"
-                       backend))))
-        (unless (and company-candidates
-                     (not (eq t company-common)))
-          (company-cancel)))))
+  (company-continue)
+  (unless company-candidates
+    (let (prefix)
+      (dolist (backend company-backends)
+        (unless (fboundp backend)
+          (ignore-errors (require backend nil t)))
+        (if (fboundp backend)
+            (when (setq prefix (funcall backend 'prefix))
+              (when (company-should-complete prefix)
+                (setq company-backend backend
+                      company-prefix prefix
+                      company-candidates
+                      (funcall company-backend 'candidates prefix)
+                      company-selection 0)
+                (unless (funcall company-backend 'sorted)
+                  (setq company-candidates
+                        (sort company-candidates 'string<)))
+                (company-call-frontends 'update))
+              (return prefix))
+          (unless (memq backend company-disabled-backends)
+            (push backend company-disabled-backends)
+            (message "Company back-end '%s' could not be initialized"
+                     backend))))))
+  (if (or (not company-candidates)
+          (eq t (let ((completion-ignore-case (funcall company-backend
+                                                       'ignore-case)))
+                  (setq company-common
+                        (try-completion company-prefix company-candidates)))))
+      (company-cancel)
+    (setq company-point (point))))
 
 (defun company-cancel ()
   (setq company-backend nil

commit ba11b654e61b5912851bc7fcf239131be7bc13c5
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 14 19:33:38 2009 +0100

    Added DWIM complete command.

diff --git a/company.el b/company.el
index 5f57337..f6a7f51 100644
--- a/company.el
+++ b/company.el
@@ -127,7 +127,7 @@
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap (kbd "M-<return>") 'company-complete-selection)
-    (define-key keymap "\t" 'company-complete-common)
+    (define-key keymap "\t" 'company-complete)
     keymap))
 
 ;;;###autoload
@@ -309,6 +309,15 @@
   (when (company-manual-begin)
     (insert (company-strip-prefix company-common))))
 
+(defun company-complete ()
+  (interactive)
+  (when (company-manual-begin)
+    (if (or company-selection-changed
+            (eq last-command 'company-complete-common))
+        (call-interactively 'company-complete-selection)
+      (call-interactively 'company-complete-common)
+      (setq this-command 'company-complete-common))))
+
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defconst company-space-strings-limit 100)

commit f8e020101fea5bb81987929597032e3c7f34212e
Author: Nikolaj Schumacher <address@hidden>
Date:   Sat Mar 14 18:36:23 2009 +0100

    Added count of hidden items to tooltip.

diff --git a/company.el b/company.el
index dbdfba2..5f57337 100644
--- a/company.el
+++ b/company.el
@@ -341,6 +341,24 @@
 (defvar company-tooltip-offset 0)
 (make-variable-buffer-local 'company-tooltip-offset)
 
+(defun company-pseudo-tooltip-update-offset (selection num-lines limit)
+
+  (decf limit 2)
+  (setq company-tooltip-offset
+        (max (min selection company-tooltip-offset)
+             (- selection -1 limit)))
+
+  (when (<= company-tooltip-offset 1)
+    (incf limit)
+    (setq company-tooltip-offset 0))
+
+  (when (>= company-tooltip-offset (- num-lines limit 1))
+    (incf limit)
+    (when (= selection (1- num-lines))
+      (setq company-tooltip-offset (max (1- company-tooltip-offset) 0))))
+
+  limit)
+
 ;;; propertize
 
 (defun company-fill-propertize (line width selected)
@@ -392,26 +410,49 @@
   (unless lines (error "No text provided"))
   (save-excursion
 
-    ;; Scroll to offset.
-    (setq company-tooltip-offset
-          (max (min selection company-tooltip-offset)
-               (- selection -1 company-tooltip-limit)))
+    (let ((limit (max company-tooltip-limit 3))
+          (len (length lines))
+          width
+          lines-copy
+          previous
+          remainder
+          new)
+
+      ;; Scroll to offset.
+      (setq limit (company-pseudo-tooltip-update-offset selection len limit))
 
-    (setq lines (nthcdr company-tooltip-offset lines))
-    (decf selection company-tooltip-offset)
+      (when (> company-tooltip-offset 0)
+        (setq previous (format "...(%d)" company-tooltip-offset)))
+
+      (setq remainder (- len limit company-tooltip-offset)
+            remainder (when (> remainder 0)
+                        (setq remainder (format "...(%d)" remainder))))
+
+      (decf selection company-tooltip-offset)
+      (setq width (min (length previous) (length remainder))
+            lines (nthcdr company-tooltip-offset lines)
+            len (min limit (length lines))
+            lines-copy lines)
 
-    (let ((width 0)
-          (lines-copy lines)
-          (len (min company-tooltip-limit (length lines)))
-          new)
       (dotimes (i len)
         (setq width (max (length (pop lines-copy)) width)))
       (setq width (min width (- (window-width) column)))
+
+      (when previous
+        (push (propertize (company-safe-substring previous 0 width)
+                          'face 'company-tooltip)
+              new))
+
       (dotimes (i len)
         (push (company-fill-propertize (company-reformat (pop lines))
                                        width (equal i selection))
               new))
 
+      (when remainder
+        (push (propertize (company-safe-substring remainder 0 width)
+                          'face 'company-tooltip)
+              new))
+
       (setq lines (nreverse new)))
 
     (move-to-column 0)

commit c9c3c3b325b3eed1531403e355b72c51d8bb61d3
Author: Nikolaj Schumacher <address@hidden>
Date:   Fri Mar 13 20:43:17 2009 +0100

    Integrated company-fill-propertize-lines into company-pseudo-tooltip-show.

diff --git a/company.el b/company.el
index 97470b4..dbdfba2 100644
--- a/company.el
+++ b/company.el
@@ -355,20 +355,6 @@
                                      'company-tooltip-common)) line)
   line)
 
-(defun company-fill-propertize-lines (column lines selection)
-  (let ((width 0)
-        (lines-copy lines)
-        (len (min company-tooltip-limit (length lines)))
-        new)
-    (dotimes (i len)
-      (setq width (max (length (pop lines-copy)) width)))
-    (setq width (min width (- (window-width) column)))
-    (dotimes (i len)
-      (push (company-fill-propertize (company-reformat (pop lines))
-                                     width (equal i selection))
-            new))
-    (nreverse new)))
-
 ;;; replace
 
 (defun company-buffer-lines (beg end)
@@ -414,8 +400,19 @@
     (setq lines (nthcdr company-tooltip-offset lines))
     (decf selection company-tooltip-offset)
 
-    (setq lines (company-fill-propertize-lines column lines selection))
-
+    (let ((width 0)
+          (lines-copy lines)
+          (len (min company-tooltip-limit (length lines)))
+          new)
+      (dotimes (i len)
+        (setq width (max (length (pop lines-copy)) width)))
+      (setq width (min width (- (window-width) column)))
+      (dotimes (i len)
+        (push (company-fill-propertize (company-reformat (pop lines))
+                                       width (equal i selection))
+              new))
+
+      (setq lines (nreverse new)))
 
     (move-to-column 0)
 

commit 1893a2d9f770e1f034424a7099315658829f65b6
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 12 23:04:08 2009 +0100

    Changed offset calculation to resemble scrolling.

diff --git a/company.el b/company.el
index 6166363..97470b4 100644
--- a/company.el
+++ b/company.el
@@ -183,10 +183,6 @@
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
-(defsubst company-offset (display-limit)
-  (let ((offset (- company-selection display-limit -1)))
-    (max offset 0)))
-
 (defsubst company-reformat (candidate)
   ;; company-ispell needs this, because the results are always lower-case
   ;; It's mory efficient to fix it only when they are displayed.
@@ -342,6 +338,9 @@
 (defvar company-pseudo-tooltip-overlay nil)
 (make-variable-buffer-local 'company-pseudo-tooltip-overlay)
 
+(defvar company-tooltip-offset 0)
+(make-variable-buffer-local 'company-tooltip-offset)
+
 ;;; propertize
 
 (defun company-fill-propertize (line width selected)
@@ -408,9 +407,12 @@
   (save-excursion
 
     ;; Scroll to offset.
-    (let ((offset (company-offset company-tooltip-limit)))
-      (setq lines (nthcdr offset lines))
-      (decf selection offset))
+    (setq company-tooltip-offset
+          (max (min selection company-tooltip-offset)
+               (- selection -1 company-tooltip-limit)))
+
+    (setq lines (nthcdr company-tooltip-offset lines))
+    (decf selection company-tooltip-offset)
 
     (setq lines (company-fill-propertize-lines column lines selection))
 
@@ -447,7 +449,8 @@
     ('pre-command (company-pseudo-tooltip-hide))
     ('post-command (company-pseudo-tooltip-show-at-point
                     (- (point) (length company-prefix))))
-    ('hide (company-pseudo-tooltip-hide))))
+    ('hide (company-pseudo-tooltip-hide)
+           (setq company-tooltip-offset 0))))
 
 (defun company-pseudo-tooltip-unless-just-one-frontend (command)
   (unless (and (eq command 'post-command)

commit d313af8df220232f24cae1494070bf86105f0346
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 12 18:35:12 2009 +0100

    Added ispell back-end.

diff --git a/company-ispell.el b/company-ispell.el
new file mode 100644
index 0000000..a581170
--- /dev/null
+++ b/company-ispell.el
@@ -0,0 +1,21 @@
+(require 'company)
+(require 'ispell)
+(eval-when-compile (require 'cl))
+
+(defcustom company-ispell-dictionary nil
+  "*Dictionary to use for `company-ispell'.
+If nil, use `ispell-complete-word-dict'."
+  :group 'company
+  :type '(choice (const :tag "default (nil)" nil)
+                 (file :tag "dictionary" t)))
+
+(defun company-ispell (command &optional arg &rest ignored)
+  (case command
+    ('prefix (company-grab "\\<\\w+\\>"))
+    ('candidates (lookup-words arg (or company-ispell-dictionary
+                                       ispell-complete-word-dict)))
+    ('sorted t)
+    ('ignore-case t)))
+
+(provide 'company-ispell)
+;;; company-ispell.el ends here
diff --git a/company.el b/company.el
index a5b4662..6166363 100644
--- a/company.el
+++ b/company.el
@@ -93,7 +93,8 @@
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
-(defcustom company-backends '(company-elisp company-nxml company-css)
+(defcustom company-backends '(company-elisp company-nxml company-css
+                              company-ispell)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))
@@ -186,6 +187,11 @@
   (let ((offset (- company-selection display-limit -1)))
     (max offset 0)))
 
+(defsubst company-reformat (candidate)
+  ;; company-ispell needs this, because the results are always lower-case
+  ;; It's mory efficient to fix it only when they are displayed.
+  (concat company-prefix (substring candidate (length company-prefix))))
+
 (defsubst company-should-complete (prefix)
   (and (eq company-idle-delay t)
        (>= (length prefix) company-minimum-prefix-length)))
@@ -226,8 +232,7 @@
 
 (defun company-begin ()
   (or (company-continue-or-cancel)
-      (let ((completion-ignore-case nil) ;; TODO: make this optional
-            prefix)
+      (let (prefix)
         (dolist (backend company-backends)
           (unless (fboundp backend)
             (ignore-errors (require backend nil t)))
@@ -239,7 +244,9 @@
                         company-candidates
                         (funcall company-backend 'candidates prefix)
                         company-common
-                        (try-completion prefix company-candidates)
+                        (let ((completion-ignore-case (funcall backend
+                                                               'ignore-case)))
+                          (try-completion prefix company-candidates))
                         company-selection 0
                         company-point (point))
                   (unless (funcall company-backend 'sorted)
@@ -358,7 +365,8 @@
       (setq width (max (length (pop lines-copy)) width)))
     (setq width (min width (- (window-width) column)))
     (dotimes (i len)
-      (push (company-fill-propertize (pop lines) width (equal i selection))
+      (push (company-fill-propertize (company-reformat (pop lines))
+                                     width (equal i selection))
             new))
     (nreverse new)))
 
@@ -505,7 +513,7 @@
         (len -1)
         comp msg)
     (while candidates
-      (setq comp (pop candidates)
+      (setq comp (company-reformat (pop candidates))
             len (+ len 1 (length comp)))
       (if (>= len limit)
           (setq candidates nil)

commit 3eed36483f4e1d7fa8ea6b900440f4c6342874ad
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 12 13:33:15 2009 +0100

    Added support for CSS.

diff --git a/company-css.el b/company-css.el
new file mode 100644
index 0000000..af513ca
--- /dev/null
+++ b/company-css.el
@@ -0,0 +1,277 @@
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defconst company-css-property-alist
+  ;; see http://www.w3.org/TR/CSS21/propidx.html
+  '(("azimuth" angle "left-side" "far-left" "left" "center-left" "center"
+     "center-right" "right" "far-right" "right-side" "behind" "leftwards"
+     "rightwards")
+    ("background" background-color background-image background-repeat
+     background-attachment background-position)
+    ("background-attachment" "scroll" "fixed")
+    ("background-color" color "transparent")
+    ("background-image" uri "none")
+    ("background-position" percentage length "left" "center" "right" percentage
+     length "top" "center" "bottom" "left" "center" "right" "top" "center"
+     "bottom")
+    ("background-repeat" "repeat" "repeat-x" "repeat-y" "no-repeat")
+    ("border" border-width border-style border-color)
+    ("border-bottom" border)
+    ("border-bottom-color" border-color)
+    ("border-bottom-style" border-style)
+    ("border-bottom-width" border-width)
+    ("border-collapse" "collapse" "separate")
+    ("border-color" color "transparent")
+    ("border-left" border)
+    ("border-left-color" border-color)
+    ("border-left-style" border-style)
+    ("border-left-width" border-width)
+    ("border-right" border)
+    ("border-right-color" border-color)
+    ("border-right-style" border-style)
+    ("border-right-width" border-width)
+    ("border-spacing" length length)
+    ("border-style" border-style)
+    ("border-top" border)
+    ("border-top-color" border-color)
+    ("border-top-style" border-style)
+    ("border-top-width" border-width)
+    ("border-width" border-width)
+    ("bottom" length percentage "auto")
+    ("caption-side" "top" "bottom")
+    ("clear" "none" "left" "right" "both")
+    ("clip" shape "auto")
+    ("color" color)
+    ("content" "normal" "none" string uri counter "attr()" "open-quote"
+     "close-quote" "no-open-quote" "no-close-quote")
+    ("counter-increment" identifier integer "none")
+    ("counter-reset" identifier integer "none")
+    ("cue" cue-before cue-after)
+    ("cue-after" uri "none")
+    ("cue-before" uri "none")
+    ("cursor" uri "*" "auto" "crosshair" "default" "pointer" "move" "e-resize"
+     "ne-resize" "nw-resize" "n-resize" "se-resize" "sw-resize" "s-resize"
+     "w-resize" "text" "wait" "help" "progress")
+    ("direction" "ltr" "rtl")
+    ("display" "inline" "block" "list-item" "run-in" "inline-block" "table"
+     "inline-table" "table-row-group" "table-header-group" "table-footer-group"
+     "table-row" "table-column-group" "table-column" "table-cell"
+     "table-caption" "none")
+    ("elevation" angle "below" "level" "above" "higher" "lower")
+    ("empty-cells" "show" "hide")
+    ("float" "left" "right" "none")
+    ("font" font-style font-variant font-weight font-size "/" line-height
+     font-family "caption" "icon" "menu" "message-box" "small-caption"
+     "status-bar")
+    ("font-family" family-name generic-family)
+    ("font-size" absolute-size relative-size length percentage)
+    ("font-style" "normal" "italic" "oblique")
+    ("font-variant" "normal" "small-caps")
+    ("font-weight" "normal" "bold" "bolder" "lighter" "100" "200" "300" "400"
+     "500" "600" "700" "800" "900")
+    ("height" length percentage "auto")
+    ("left" length percentage "auto")
+    ("letter-spacing" "normal" length)
+    ("line-height" "normal" number length percentage)
+    ("list-style" list-style-type list-style-position list-style-image)
+    ("list-style-image" uri "none")
+    ("list-style-position" "inside" "outside")
+    ("list-style-type" "disc" "circle" "square" "decimal" 
"decimal-leading-zero"
+     "lower-roman" "upper-roman" "lower-greek" "lower-latin" "upper-latin"
+     "armenian" "georgian" "lower-alpha" "upper-alpha" "none")
+    ("margin" margin-width)
+    ("margin-bottom" margin-width)
+    ("margin-left" margin-width)
+    ("margin-right" margin-width)
+    ("margin-top" margin-width)
+    ("max-height" length percentage "none")
+    ("max-width" length percentage "none")
+    ("min-height" length percentage)
+    ("min-width" length percentage)
+    ("orphans" integer)
+    ("outline" outline-color outline-style outline-width)
+    ("outline-color" color "invert")
+    ("outline-style" border-style)
+    ("outline-width" border-width)
+    ("overflow" "visible" "hidden" "scroll" "auto")
+    ("padding" padding-width)
+    ("padding-bottom" padding-width)
+    ("padding-left" padding-width)
+    ("padding-right" padding-width)
+    ("padding-top" padding-width)
+    ("page-break-after" "auto" "always" "avoid" "left" "right")
+    ("page-break-before" "auto" "always" "avoid" "left" "right")
+    ("page-break-inside" "avoid" "auto")
+    ("pause" time percentage)
+    ("pause-after" time percentage)
+    ("pause-before" time percentage)
+    ("pitch" frequency "x-low" "low" "medium" "high" "x-high")
+    ("pitch-range" number)
+    ("play-during" uri "mix" "repeat" "auto" "none")
+    ("position" "static" "relative" "absolute" "fixed")
+    ("quotes" string string "none")
+    ("richness" number)
+    ("right" length percentage "auto")
+    ("speak" "normal" "none" "spell-out")
+    ("speak-header" "once" "always")
+    ("speak-numeral" "digits" "continuous")
+    ("speak-punctuation" "code" "none")
+    ("speech-rate" number "x-slow" "slow" "medium" "fast" "x-fast" "faster"
+     "slower")
+    ("stress" number)
+    ("table-layout" "auto" "fixed")
+    ("text-align" "left" "right" "center" "justify")
+    ("text-decoration" "none" "underline" "overline" "line-through" "blink")
+    ("text-indent" length percentage)
+    ("text-transform" "capitalize" "uppercase" "lowercase" "none")
+    ("top" length percentage "auto")
+    ("unicode-bidi" "normal" "embed" "bidi-override")
+    ("vertical-align" "baseline" "sub" "super" "top" "text-top" "middle"
+     "bottom" "text-bottom" percentage length)
+    ("visibility" "visible" "hidden" "collapse")
+    ("voice-family" specific-voice generic-voice "*" specific-voice
+     generic-voice)
+    ("volume" number percentage "silent" "x-soft" "soft" "medium" "loud"
+     "x-loud")
+    ("white-space" "normal" "pre" "nowrap" "pre-wrap" "pre-line")
+    ("widows" integer)
+    ("width" length percentage "auto")
+    ("word-spacing" "normal" length)
+    ("z-index" "auto" integer))
+  "A list of CSS properties and their possible values.")
+
+(defconst company-css-value-classes
+  '((absolute-size "xx-small" "x-small" "small" "medium" "large" "x-large"
+                   "xx-large")
+    (border-style "none" "hidden" "dotted" "dashed" "solid" "double" "groove"
+                  "ridge" "inset" "outset")
+    (color "aqua" "black" "blue" "fuchsia" "gray" "green" "lime" "maroon" 
"navy"
+           "olive" "orange" "purple" "red" "silver" "teal" "white" "yellow")
+    (counter "counter(,)")
+    (family-name "Courier" "Helvetica" "Times")
+    (generic-family "serif" "sans-serif" "cursive" "fantasy" "monospace")
+    (generic-voice "male" "female" "child")
+    (margin-width "auto") ;; length percentage
+    (relative-size "larger" "smaller")
+    (shape "rect(,,,)")
+    (uri "url()"))
+  "A list of CSS property value classes and their contents.")
+;; missing, because not completable
+;; <angle><frequency><identifier><integer><length><number><padding-width>
+;; <percentage><specific-voice><string><time><uri>
+
+(defconst company-css-html-tags
+  '("a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo"
+    "big" "blockquote" "body" "br" "button" "caption" "center" "cite" "code"
+    "col" "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset"
+    "font" "form" "frame" "frameset" "h1" "h2" "h3" "h4" "h5" "h6" "head" "hr"
+    "html" "i" "iframe" "img" "input" "ins" "isindex" "kbd" "label" "legend"
+    "li" "link" "map" "menu" "meta" "noframes" "noscript" "object" "ol"
+    "optgroup" "option" "p" "param" "pre" "q" "s" "samp" "script" "select"
+    "small" "span" "strike" "strong" "style" "sub" "sup" "table" "tbody" "td"
+    "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var")
+  "A list of HTML tags for use in CSS completion.")
+
+(defconst company-css-pseudo-classes
+  '("active" "after" "before" "first" "first-child" "first-letter" "first-line"
+    "focus" "hover" "lang" "left" "link" "right" "visited")
+  "Identifiers for CSS pseudo-elements and pseudo-classes.")
+
+(defconst company-css-property-cache (make-hash-table :size 115 :test 'equal))
+
+(defun company-css-property-values (attribute)
+  "Access the `company-css-property-alist' cached and flattened."
+  (or (gethash attribute company-css-property-cache)
+      (let (results)
+        (dolist (value (cdr (assoc attribute company-css-property-alist)))
+          (if (symbolp value)
+              (dolist (child (or (cdr (assoc value company-css-value-classes))
+                                 (company-css-property-values
+                                  (symbol-name value))))
+                (add-to-list 'results child))
+            (add-to-list 'results value)))
+        (setq results (sort results 'string<))
+        (puthash attribute results company-css-property-cache)
+        results)))
+
+;;; bracket detection
+
+(defconst company-css-braces-syntax-table
+  (let ((table (make-syntax-table)))
+    (setf (aref table ?{) '(4 . 125))
+    (setf (aref table ?}) '(5 . 123))
+    table)
+  "A syntax table giving { and } paren syntax.")
+
+(defun company-css-inside-braces-p ()
+  "Return non-nil, if point is within matched { and }."
+  (ignore-errors
+    (with-syntax-table company-css-braces-syntax-table
+      (let ((parse-sexp-ignore-comments t))
+        (scan-lists (point) -1 1)))))
+
+;;; tags
+(defconst company-css-tag-regexp
+  (concat "\\(?:\\`\\|}\\)[[:space:]]*"
+          ;; multiple
+          "\\(?:"
+          ;; previous tags:
+          "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
+          ;; space or selectors
+          "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
+          "\\)*"
+          "\\(\\(?:#\\|\\_<[[:alpha:]]\\)\\(?:[[:alnum:]-#]*\\_>\\)?\\_>\\|\\)"
+          "\\=")
+  "A regular expression matching CSS tags")
+
+;;; pseudo id
+(defconst company-css-pseudo-regexp
+  (concat "\\(?:\\`\\|}\\)[[:space:]]*"
+          ;; multiple
+          "\\(?:"
+          ;; previous tags:
+          "\\(?:#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\(?:\\[[^]]*\\]\\)?"
+          ;; space or delimiters
+          "\\(?:[[:space:]]+\\|[[:space:]]*[+,>][[:space:]]*\\)"
+          "\\)*"
+          "\\(?:\\(?:\\#\\|\\_<[[:alpha:]]\\)[[:alnum:]-#]*\\):"
+          "\\([[:alpha:]-]+\\_>\\|\\)\\_>\\=")
+  "A regular expression matching CSS pseudo classes")
+
+;;; properties
+
+(defun company-css-grab-property ()
+  "Return the CSS property before point, if any.
+Returns \"\" if no property found, but feasible at this position."
+  (when (company-css-inside-braces-p)
+    (or (company-grab "\\_<[[:alpha:]-]+\\_>\\=")
+        (company-grab "{\\|[[:space:]]" 1))))
+
+;;; values
+(defconst company-css-property-value-regexp
+  "\\_<\\([[:alpha:]-]+\\):\\(?:[^};]*[[:space:]]+\\)?\\([^};]*\\_>\\|\\)\\="
+  "A regular expression matching CSS tags")
+
+(defun company-css (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'css-mode)
+                  (or (company-grab company-css-tag-regexp 1)
+                      (company-grab company-css-pseudo-regexp 1)
+                      (company-grab company-css-property-value-regexp 2)
+                      (company-css-grab-property))))
+    ('candidates
+     (cond
+      ((company-grab company-css-tag-regexp 1)
+       (all-completions arg company-css-html-tags))
+      ((company-grab company-css-pseudo-regexp 1)
+       (all-completions arg company-css-pseudo-classes))
+      ((company-grab company-css-property-value-regexp 2)
+       (all-completions arg
+                        (company-css-property-values
+                         (company-grab company-css-property-value-regexp 1))))
+      ((company-css-grab-property)
+       (all-completions arg company-css-property-alist))))
+    ('sorted t)))
+
+(provide 'company-css)
+;;; company-css.el ends here
diff --git a/company.el b/company.el
index d4fd307..a5b4662 100644
--- a/company.el
+++ b/company.el
@@ -93,7 +93,7 @@
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
-(defcustom company-backends '(company-elisp company-nxml)
+(defcustom company-backends '(company-elisp company-nxml company-css)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))

commit 8a99641b178876e1c309bdbcfca680807c1b2418
Author: Nikolaj Schumacher <address@hidden>
Date:   Thu Mar 12 11:02:14 2009 +0100

    Added nxml-mode support.

diff --git a/company-nxml.el b/company-nxml.el
new file mode 100644
index 0000000..18badc8
--- /dev/null
+++ b/company-nxml.el
@@ -0,0 +1,102 @@
+(require 'company)
+(require 'nxml-mode)
+(require 'rng-nxml)
+(eval-when-compile (require 'cl))
+
+(defconst company-nxml-token-regexp
+  "\\(?:[_[:alpha:]][-._[:alnum:]]*\\_>\\)")
+
+(defvar company-nxml-in-attribute-value-regexp
+  (replace-regexp-in-string "w" company-nxml-token-regexp
+   "<w\\(?::w\\)?\
+\\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
+[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
+[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
+\\(\"\\([^\"]*\\>\\)\\|'\\([^']*\\>\\)\\)\\="
+   t t))
+
+(defvar company-nxml-in-tag-name-regexp
+  (replace-regexp-in-string "w" company-nxml-token-regexp
+                            "<\\(/?w\\(?::w?\\)?\\)?\\=" t t))
+
+(defun company-nxml-all-completions (prefix alist)
+  (let ((candidates (mapcar 'cdr alist))
+        (case-fold-search nil)
+        filtered)
+    (when (cdar rng-open-elements)
+      (push (concat "/" (cdar rng-open-elements)) candidates))
+    (setq candidates (sort (all-completions prefix candidates) 'string<))
+    (while candidates
+      (unless (equal (car candidates) (car filtered))
+        (push (car candidates) filtered))
+      (pop candidates))
+    (nreverse filtered)))
+
+(defmacro company-nxml-prepared (&rest body)
+  (declare (indent 0) (debug t))
+  `(let ((lt-pos (save-excursion (search-backward "<" nil t)))
+         xmltok-dtd)
+     (when (and lt-pos (= (rng-set-state-after lt-pos) lt-pos))
+       ,@body)))
+
+(defun company-nxml-tag (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'nxml-mode)
+                  rng-validate-mode
+                  (company-grab company-nxml-in-tag-name-regexp 1)))
+    ('candidates (company-nxml-prepared
+                   (company-nxml-all-completions arg
+                    (rng-match-possible-start-tag-names))))
+    ('sorted t)))
+
+(defun company-nxml-attribute (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'nxml-mode)
+                  rng-validate-mode
+                  (memq (char-after) '(?\  ?\t ?\n)) ;; outside word
+                  (company-grab rng-in-attribute-regex 1)))
+    ('candidates (company-nxml-prepared
+                   (and (rng-adjust-state-for-attribute
+                         lt-pos (- (point) (length arg)))
+                        (company-nxml-all-completions arg
+                         (rng-match-possible-attribute-names)))))
+    ('sorted t)))
+
+(defun company-nxml-attribute-value (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'nxml-mode)
+                  rng-validate-mode
+                  (and (memq (char-after) '(?' ?\" ?\  ?\t ?\n)) ;; outside 
word
+                       (looking-back company-nxml-in-attribute-value-regexp)
+                       (or (match-string-no-properties 4)
+                           (match-string-no-properties 5)
+                           ""))))
+    ('candidates (company-nxml-prepared
+                   (let (attr-start attr-end colon)
+                     (and (looking-back rng-in-attribute-value-regex lt-pos)
+                          (setq colon (match-beginning 2)
+                                attr-start (match-beginning 1)
+                                attr-end (match-end 1))
+                          (rng-adjust-state-for-attribute lt-pos attr-start)
+                          (rng-adjust-state-for-attribute-value
+                           attr-start colon attr-end)
+                          (all-completions arg
+                           (rng-match-possible-value-strings))))))))
+
+(defun company-nxml (command &optional arg &rest ignored)
+  (case command
+    ('prefix (or (company-nxml-tag 'prefix)
+                 (company-nxml-attribute 'prefix)
+                 (company-nxml-attribute-value 'prefix)))
+    ('candidates (cond
+                  ((company-nxml-tag 'prefix)
+                   (company-nxml-tag 'candidates arg))
+                  ((company-nxml-attribute 'prefix)
+                   (company-nxml-attribute 'candidates arg))
+                  ((company-nxml-attribute-value 'prefix)
+                   (sort (company-nxml-attribute-value 'candidates arg)
+                         'string<))))
+    ('sorted t)))
+
+(provide 'company-nxml)
+;;; company-nxml.el ends here
diff --git a/company.el b/company.el
index af0f63a..d4fd307 100644
--- a/company.el
+++ b/company.el
@@ -93,7 +93,7 @@
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
-(defcustom company-backends '(company-elisp)
+(defcustom company-backends '(company-elisp company-nxml)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))

commit de72f1d32110cdaa5ad5a5ec852c25559a23a1a4
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 17:07:40 2009 +0100

    Moved back-ends to separate files.

diff --git a/company-elisp.el b/company-elisp.el
new file mode 100644
index 0000000..b915423
--- /dev/null
+++ b/company-elisp.el
@@ -0,0 +1,23 @@
+(require 'company)
+(eval-when-compile (require 'cl))
+
+(defvar company-lisp-symbol-regexp
+  "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
+
+(defun company-grab-lisp-symbol ()
+  (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
+    (unless (and (company-in-string-or-comment (- (point) (length prefix)))
+                 (/= (char-before (- (point) (length prefix))) ?`))
+      prefix)))
+
+(defun company-elisp (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'emacs-lisp-mode)
+                  (company-grab-lisp-symbol)))
+    ('candidates (let ((completion-ignore-case nil))
+                   (all-completions arg obarray
+                                    (lambda (symbol) (or (boundp symbol)
+                                                         (fboundp 
symbol))))))))
+
+(provide 'company-elisp)
+;;; company-elisp.el ends here
diff --git a/company.el b/company.el
index 6ec1d49..af0f63a 100644
--- a/company.el
+++ b/company.el
@@ -93,7 +93,7 @@
                                 company-preview-if-just-one-frontend)
                          (function :tag "custom function" nil))))
 
-(defcustom company-backends '(company-elisp-completion)
+(defcustom company-backends '(company-elisp)
   "*"
   :group 'company
   :type '(repeat (function :tag "function" nil)))
@@ -154,26 +154,6 @@
   (let ((pos (syntax-ppss)))
     (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
 
-;;; elisp
-
-(defvar company-lisp-symbol-regexp
-  "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
-
-(defun company-grab-lisp-symbol ()
-  (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
-    (unless (and (company-in-string-or-comment (- (point) (length prefix)))
-                 (/= (char-before (- (point) (length prefix))) ?`))
-      prefix)))
-
-(defun company-elisp-completion (command &optional arg &rest ignored)
-  (case command
-    ('prefix (and (eq major-mode 'emacs-lisp-mode)
-                  (company-grab-lisp-symbol)))
-    ('candidates (let ((completion-ignore-case nil))
-                   (all-completions arg obarray
-                                    (lambda (symbol) (or (boundp symbol)
-                                                         (fboundp 
symbol))))))))
-
 ;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-backend nil)
@@ -197,6 +177,8 @@
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
+(defvar company-disabled-backends nil)
+
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
@@ -247,19 +229,28 @@
       (let ((completion-ignore-case nil) ;; TODO: make this optional
             prefix)
         (dolist (backend company-backends)
-          (when (setq prefix (funcall backend 'prefix))
-            (when (company-should-complete prefix)
-              (setq company-backend backend
-                    company-prefix prefix
-                    company-candidates
-                    (funcall company-backend 'candidates prefix)
-                    company-common (try-completion prefix company-candidates)
-                    company-selection 0
-                    company-point (point))
-              (unless (funcall company-backend 'sorted)
-                (setq company-candidates (sort company-candidates 'string<)))
-              (company-call-frontends 'update))
-            (return prefix)))
+          (unless (fboundp backend)
+            (ignore-errors (require backend nil t)))
+          (if (fboundp backend)
+              (when (setq prefix (funcall backend 'prefix))
+                (when (company-should-complete prefix)
+                  (setq company-backend backend
+                        company-prefix prefix
+                        company-candidates
+                        (funcall company-backend 'candidates prefix)
+                        company-common
+                        (try-completion prefix company-candidates)
+                        company-selection 0
+                        company-point (point))
+                  (unless (funcall company-backend 'sorted)
+                    (setq company-candidates
+                          (sort company-candidates 'string<)))
+                  (company-call-frontends 'update))
+                (return prefix))
+            (unless (memq backend company-disabled-backends)
+              (push backend company-disabled-backends)
+              (message "Company back-end '%s' could not be initialized"
+                       backend))))
         (unless (and company-candidates
                      (not (eq t company-common)))
           (company-cancel)))))

commit bc7e72a7937d96790c2a5d9e27fc004b44d063a7
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 17:14:19 2009 +0100

    Fixed pseudo tooltips on the last line if no trailing newline.

diff --git a/company.el b/company.el
index f7fe240..6ec1d49 100644
--- a/company.el
+++ b/company.el
@@ -388,7 +388,7 @@
           new
           (company-safe-substring old (+ offset (length new)))))
 
-(defun company-modified-substring (beg end lines column)
+(defun company-modified-substring (beg end lines column nl)
   (let ((old (company-buffer-lines beg end))
         new)
     ;; Inject into old lines.
@@ -397,7 +397,8 @@
     ;; Append whole new lines.
     (while lines
       (push (company-modify-line "" (pop lines) column) new))
-    (concat (mapconcat 'identity (nreverse new) "\n")
+    (concat (when nl "\n")
+            (mapconcat 'identity (nreverse new) "\n")
             "\n")))
 
 ;; show
@@ -416,8 +417,9 @@
 
 
     (move-to-column 0)
-    (move-to-window-line row)
-    (let ((beg (point))
+
+    (let ((nl (< (move-to-window-line row) row))
+          (beg (point))
           (end (save-excursion
                  (move-to-window-line (min (window-height)
                                            (+ row company-tooltip-limit)))
@@ -427,7 +429,7 @@
       (setq company-pseudo-tooltip-overlay (make-overlay beg end))
 
       (overlay-put company-pseudo-tooltip-overlay 'before-string
-                   (company-modified-substring beg end lines column))
+                   (company-modified-substring beg end lines column nl))
       (overlay-put company-pseudo-tooltip-overlay 'invisible t)
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 

commit 3c53fd28fa796b8bad33cb019b67c5eeec479845
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 15:12:29 2009 +0100

    Sort candidates.

diff --git a/company.el b/company.el
index dbc51d3..f7fe240 100644
--- a/company.el
+++ b/company.el
@@ -256,6 +256,8 @@
                     company-common (try-completion prefix company-candidates)
                     company-selection 0
                     company-point (point))
+              (unless (funcall company-backend 'sorted)
+                (setq company-candidates (sort company-candidates 'string<)))
               (company-call-frontends 'update))
             (return prefix)))
         (unless (and company-candidates

commit d4761e94c9e13c9876a32520a4144de4f0bfd7e1
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 14:41:16 2009 +0100

    Added more detailed front-end options.

diff --git a/company.el b/company.el
index d109d3c..dbc51d3 100644
--- a/company.el
+++ b/company.el
@@ -1,5 +1,9 @@
 (eval-when-compile (require 'cl))
 
+(add-to-list 'debug-ignored-errors
+             "^Pseudo tooltip frontend cannot be used twice$")
+(add-to-list 'debug-ignored-errors "^Preview frontend cannot be used twice$")
+
 (defgroup company nil
   ""
   :group 'abbrev
@@ -57,12 +61,37 @@
   "*"
   :group 'company)
 
+(defun company-frontends-set (variable value)
+  ;; uniquify
+  (let ((remainder value))
+    (setcdr remainder (delq (car remainder) (cdr remainder))))
+  (and (memq 'company-pseudo-tooltip-unless-just-one-frontend value)
+       (memq 'company-pseudo-tooltip-frontend value)
+       (error "Pseudo tooltip frontend cannot be used twice"))
+  (and (memq 'company-preview-if-just-one-frontend value)
+       (memq 'company-preview-frontend value)
+       (error "Preview frontend cannot be used twice"))
+  ;; preview must come last
+  (dolist (f '(company-preview-if-just-one-frontend company-preview-frontend))
+    (when (memq f value)
+      (setq value (append (delq f value) (list f)))))
+  (set variable value))
+
 (defcustom company-frontends '(company-echo-frontend
-                               company-pseudo-tooltip-frontend
-                               company-completion-frontend)
+                               company-pseudo-tooltip-unless-just-one-frontend
+                               company-preview-if-just-one-frontend)
   "*"
+  :set 'company-frontends-set
   :group 'company
-  :type '(repeat (function :tag "function" nil)))
+  :type '(repeat (choice (const :tag "echo" company-echo-frontend)
+                         (const :tag "pseudo tooltip"
+                                company-pseudo-tooltip-frontend)
+                         (const :tag "pseudo tooltip, multiple only"
+                                
company-pseudo-tooltip-unless-just-one-frontend)
+                         (const :tag "preview" company-preview-frontend)
+                         (const :tag "preview, unique only"
+                                company-preview-if-just-one-frontend)
+                         (function :tag "custom function" nil))))
 
 (defcustom company-backends '(company-elisp-completion)
   "*"
@@ -417,6 +446,11 @@
                     (- (point) (length company-prefix))))
     ('hide (company-pseudo-tooltip-hide))))
 
+(defun company-pseudo-tooltip-unless-just-one-frontend (command)
+  (unless (and (eq command 'post-command)
+               (not (cdr company-candidates)))
+    (company-pseudo-tooltip-frontend command)))
+
 ;;; overlay 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-preview-overlay nil)
@@ -451,6 +485,11 @@
     ('post-command (company-preview-show-at-point (point)))
     ('hide (company-preview-hide))))
 
+(defun company-preview-if-just-one-frontend (command)
+  (unless (and (eq command 'post-command)
+               (cdr company-candidates))
+    (company-preview-frontend command)))
+
 ;;; echo 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-echo-last-msg nil)

commit 20d91aae28f89c4341b0735c1d560a3b5fdcd53c
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 13:49:55 2009 +0100

    Added configurable front-end mechanism.

diff --git a/company.el b/company.el
index 8eb9477..d109d3c 100644
--- a/company.el
+++ b/company.el
@@ -57,6 +57,13 @@
   "*"
   :group 'company)
 
+(defcustom company-frontends '(company-echo-frontend
+                               company-pseudo-tooltip-frontend
+                               company-completion-frontend)
+  "*"
+  :group 'company
+  :type '(repeat (function :tag "function" nil)))
+
 (defcustom company-backends '(company-elisp-completion)
   "*"
   :group 'company
@@ -172,6 +179,10 @@
   (and (eq company-idle-delay t)
        (>= (length prefix) company-minimum-prefix-length)))
 
+(defsubst company-call-frontends (command)
+  (dolist (frontend company-frontends)
+    (funcall frontend command)))
+
 (defun company-idle-begin ()
   (and company-mode
        (not company-candidates)
@@ -215,7 +226,8 @@
                     (funcall company-backend 'candidates prefix)
                     company-common (try-completion prefix company-candidates)
                     company-selection 0
-                    company-point (point)))
+                    company-point (point))
+              (company-call-frontends 'update))
             (return prefix)))
         (unless (and company-candidates
                      (not (eq t company-common)))
@@ -229,8 +241,7 @@
         company-selection 0
         company-selection-changed nil
         company-point nil)
-  (company-pseudo-tooltip-hide)
-  (company-echo-hide))
+  (company-call-frontends 'hide))
 
 (defun company-abort ()
   (company-cancel)
@@ -238,20 +249,14 @@
   (setq company-point (point)))
 
 (defun company-pre-command ()
-  (company-preview-hide)
-  (company-pseudo-tooltip-hide)
-  (company-echo-refresh))
+  (when company-candidates
+    (company-call-frontends 'pre-command)))
 
 (defun company-post-command ()
   (unless (equal (point) company-point)
     (company-begin))
   (when company-candidates
-    (company-echo-show company-candidates))
-    (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
-                                          company-candidates
-                                          company-selection)
-    (company-preview-show-at-point (point) company-candidates
-                                   company-selection))
+    (company-call-frontends 'post-command)))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -366,7 +371,7 @@
 
 ;; show
 
-(defun company-pseudo-tooltip-show (row column lines &optional selection)
+(defun company-pseudo-tooltip-show (row column lines selection)
   (company-pseudo-tooltip-hide)
   (unless lines (error "No text provided"))
   (save-excursion
@@ -395,22 +400,29 @@
       (overlay-put company-pseudo-tooltip-overlay 'invisible t)
       (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
 
-(defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
+(defun company-pseudo-tooltip-show-at-point (pos)
   (let ((col-row (posn-col-row (posn-at-point pos))))
-    (company-pseudo-tooltip-show (1+ (cdr col-row))
-                                 (car col-row) text selection)))
+    (company-pseudo-tooltip-show (1+ (cdr col-row)) (car col-row)
+                                 company-candidates company-selection)))
 
 (defun company-pseudo-tooltip-hide ()
   (when company-pseudo-tooltip-overlay
     (delete-overlay company-pseudo-tooltip-overlay)
     (setq company-pseudo-tooltip-overlay nil)))
 
+(defun company-pseudo-tooltip-frontend (command)
+  (case command
+    ('pre-command (company-pseudo-tooltip-hide))
+    ('post-command (company-pseudo-tooltip-show-at-point
+                    (- (point) (length company-prefix))))
+    ('hide (company-pseudo-tooltip-hide))))
+
 ;;; overlay 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-preview-overlay nil)
 (make-variable-buffer-local 'company-preview-overlay)
 
-(defun company-preview-show-at-point (pos text &optional selection)
+(defun company-preview-show-at-point (pos)
   (company-preview-hide)
 
   (setq company-preview-overlay (make-overlay pos pos))
@@ -433,6 +445,12 @@
     (delete-overlay company-preview-overlay)
     (setq company-preview-overlay nil)))
 
+(defun company-preview-frontend (command)
+  (case command
+    ('pre-command (company-preview-hide))
+    ('post-command (company-preview-show-at-point (point)))
+    ('hide (company-preview-hide))))
+
 ;;; echo 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-echo-last-msg nil)
@@ -450,7 +468,7 @@
   (setq candidates (nthcdr company-selection candidates))
 
   (let ((limit (window-width (minibuffer-window)))
-        (len 0)
+        (len -1)
         comp msg)
     (while candidates
       (setq comp (pop candidates)
@@ -465,8 +483,11 @@
     (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
     (company-echo-refresh)))
 
-(defun company-echo-hide ()
-  (setq company-echo-last-msg nil))
+(defun company-echo-frontend (command)
+  (case command
+    ('pre-command (company-echo-refresh))
+    ('post-command (company-echo-show company-candidates))
+    ('hide (setq company-echo-last-msg nil))))
 
 (provide 'company)
 ;;; company.el ends here

commit efd96834fd72d0001799541660c962c945a1f571
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 14:23:38 2009 +0100

    Make sure completing stops further automatic completion.

diff --git a/company.el b/company.el
index cd7237a..8eb9477 100644
--- a/company.el
+++ b/company.el
@@ -105,7 +105,8 @@
                            company-idle-delay))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
-    (company-cancel)))
+    (company-cancel)
+    (kill-local-variable 'company-point)))
 
 ;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -174,6 +175,7 @@
 (defun company-idle-begin ()
   (and company-mode
        (not company-candidates)
+       (not (equal (point) company-point))
        (let ((company-idle-delay t))
          (company-begin)
          (company-post-command))))
@@ -230,6 +232,11 @@
   (company-pseudo-tooltip-hide)
   (company-echo-hide))
 
+(defun company-abort ()
+  (company-cancel)
+  ;; Don't start again, unless started manually.
+  (setq company-point (point)))
+
 (defun company-pre-command ()
   (company-preview-hide)
   (company-pseudo-tooltip-hide)
@@ -264,7 +271,8 @@
 (defun company-complete-selection ()
   (interactive)
   (when (company-manual-begin)
-    (insert (company-strip-prefix (nth company-selection 
company-candidates)))))
+    (insert (company-strip-prefix (nth company-selection company-candidates)))
+    (company-abort)))
 
 (defun company-complete-common ()
   (interactive)

commit fad0b1dc6453d84ae431c4b4545bb849cae1c730
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 12:59:19 2009 +0100

    Added echo front-end.

diff --git a/company.el b/company.el
index c3842ac..cd7237a 100644
--- a/company.el
+++ b/company.el
@@ -47,6 +47,16 @@
   "*"
   :group 'company)
 
+(defface company-echo nil
+  "*"
+  :group 'company)
+
+(defface company-echo-common
+  '((((background dark)) (:foreground "firebrick1"))
+    (((background light)) (:background "firebrick4")))
+  "*"
+  :group 'company)
+
 (defcustom company-backends '(company-elisp-completion)
   "*"
   :group 'company
@@ -217,21 +227,24 @@
         company-selection 0
         company-selection-changed nil
         company-point nil)
-  (company-pseudo-tooltip-hide))
+  (company-pseudo-tooltip-hide)
+  (company-echo-hide))
 
 (defun company-pre-command ()
   (company-preview-hide)
-  (company-pseudo-tooltip-hide))
+  (company-pseudo-tooltip-hide)
+  (company-echo-refresh))
 
 (defun company-post-command ()
   (unless (equal (point) company-point)
     (company-begin))
   (when company-candidates
+    (company-echo-show company-candidates))
     (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
                                           company-candidates
                                           company-selection)
     (company-preview-show-at-point (point) company-candidates
-                                   company-selection)))
+                                   company-selection))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -412,5 +425,40 @@
     (delete-overlay company-preview-overlay)
     (setq company-preview-overlay nil)))
 
+;;; echo 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-echo-last-msg nil)
+(make-variable-buffer-local 'company-echo-last-msg)
+
+(defun company-echo-refresh ()
+  (let ((message-log-max nil))
+    (if company-echo-last-msg
+        (message "%s" company-echo-last-msg)
+      (message ""))))
+
+(defun company-echo-show (candidates)
+
+  ;; Roll to selection.
+  (setq candidates (nthcdr company-selection candidates))
+
+  (let ((limit (window-width (minibuffer-window)))
+        (len 0)
+        comp msg)
+    (while candidates
+      (setq comp (pop candidates)
+            len (+ len 1 (length comp)))
+      (if (>= len limit)
+          (setq candidates nil)
+        (setq comp (propertize comp 'face 'company-echo))
+        (add-text-properties 0 (length company-common)
+                             '(face company-echo-common) comp)
+        (push comp msg)))
+
+    (setq company-echo-last-msg (mapconcat 'identity (nreverse msg) " "))
+    (company-echo-refresh)))
+
+(defun company-echo-hide ()
+  (setq company-echo-last-msg nil))
+
 (provide 'company)
 ;;; company.el ends here

commit 16c44dfbe55ed841c0a3472995f612af775d2570
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 11:10:25 2009 +0100

    Continue started completions immediately.

diff --git a/company.el b/company.el
index 4ccb7f5..c3842ac 100644
--- a/company.el
+++ b/company.el
@@ -177,25 +177,37 @@
   ;; Return non-nil if active.
   company-candidates)
 
-(defun company-begin ()
+(defun company-continue-or-cancel ()
   (when company-candidates
-    (company-cancel))
-  (let ((completion-ignore-case nil) ;; TODO: make this optional
-        prefix)
-    (dolist (backend company-backends)
-      (when (setq prefix (funcall backend 'prefix))
-        (when (company-should-complete prefix)
-          (setq company-backend backend
-                company-prefix prefix
-                company-candidates
-                (funcall company-backend 'candidates prefix)
-                company-common (try-completion prefix company-candidates)
-                company-selection 0
-                company-point (point)))
-        (return prefix)))
-    (unless (and company-candidates
-                 (not (eq t company-common)))
-      (company-cancel))))
+    (let ((old-point (- company-point (length company-prefix)))
+          (company-idle-delay t)
+          (company-minimum-prefix-length 0))
+      ;; TODO: Make more efficient.
+      (setq company-candidates nil)
+      (company-begin)
+      (unless (and company-candidates
+                   (equal old-point (- company-point (length company-prefix))))
+        (company-cancel))
+      company-candidates)))
+
+(defun company-begin ()
+  (or (company-continue-or-cancel)
+      (let ((completion-ignore-case nil) ;; TODO: make this optional
+            prefix)
+        (dolist (backend company-backends)
+          (when (setq prefix (funcall backend 'prefix))
+            (when (company-should-complete prefix)
+              (setq company-backend backend
+                    company-prefix prefix
+                    company-candidates
+                    (funcall company-backend 'candidates prefix)
+                    company-common (try-completion prefix company-candidates)
+                    company-selection 0
+                    company-point (point)))
+            (return prefix)))
+        (unless (and company-candidates
+                     (not (eq t company-common)))
+          (company-cancel)))))
 
 (defun company-cancel ()
   (setq company-backend nil

commit 56749ef21a5a04ab7fddeca907eb92f570383b0a
Author: Nikolaj Schumacher <address@hidden>
Date:   Wed Mar 11 10:09:10 2009 +0100

    Added manual start.

diff --git a/company.el b/company.el
index 7bc2e75..4ccb7f5 100644
--- a/company.el
+++ b/company.el
@@ -168,6 +168,15 @@
          (company-begin)
          (company-post-command))))
 
+(defun company-manual-begin ()
+  (and company-mode
+       (not company-candidates)
+       (let ((company-idle-delay t)
+             (company-minimum-prefix-length 0))
+         (company-begin)))
+  ;; Return non-nil if active.
+  company-candidates)
+
 (defun company-begin ()
   (when company-candidates
     (company-cancel))
@@ -216,22 +225,26 @@
 
 (defun company-select-next ()
   (interactive)
-  (setq company-selection (min (1- (length company-candidates))
-                               (1+ company-selection))
-        company-selection-changed t))
+  (when (company-manual-begin)
+    (setq company-selection (min (1- (length company-candidates))
+                                 (1+ company-selection))
+          company-selection-changed t)))
 
 (defun company-select-previous ()
   (interactive)
-  (setq company-selection (max 0 (1- company-selection))
-        company-selection-changed t))
+  (when (company-manual-begin)
+    (setq company-selection (max 0 (1- company-selection))
+          company-selection-changed t)))
 
 (defun company-complete-selection ()
   (interactive)
-  (insert (company-strip-prefix (nth company-selection company-candidates))))
+  (when (company-manual-begin)
+    (insert (company-strip-prefix (nth company-selection 
company-candidates)))))
 
 (defun company-complete-common ()
   (interactive)
-  (insert (company-strip-prefix company-common)))
+  (when (company-manual-begin)
+    (insert (company-strip-prefix company-common))))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

commit c0ca70ec242c67f55251aa53e3e33235f3b85c15
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 23:31:32 2009 +0100

    Added idle delay.

diff --git a/company.el b/company.el
index 49ffe43..7bc2e75 100644
--- a/company.el
+++ b/company.el
@@ -57,6 +57,22 @@
   :group 'company
   :type '(integer :tag "prefix length"))
 
+(defvar company-timer nil)
+
+(defun company-timer-set (variable value)
+  (set variable value)
+  (when company-timer (cancel-timer company-timer))
+  (when (numberp value)
+    (setq company-timer (run-with-idle-timer value t 'company-idle-begin))))
+
+(defcustom company-idle-delay .7
+  "*"
+  :set 'company-timer-set
+  :group 'company
+  :type '(choice (const :tag "never (nil)" nil)
+                 (const :tag "immediate (t)" t)
+                 (number :tag "seconds")))
+
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-mode-map
@@ -74,7 +90,9 @@
   (if company-mode
       (progn
         (add-hook 'pre-command-hook 'company-pre-command nil t)
-        (add-hook 'post-command-hook 'company-post-command nil t))
+        (add-hook 'post-command-hook 'company-post-command nil t)
+        (company-timer-set 'company-idle-delay
+                           company-idle-delay))
     (remove-hook 'pre-command-hook 'company-pre-command t)
     (remove-hook 'post-command-hook 'company-post-command t)
     (company-cancel)))
@@ -140,7 +158,15 @@
     (max offset 0)))
 
 (defsubst company-should-complete (prefix)
-  (>= (length prefix) company-minimum-prefix-length))
+  (and (eq company-idle-delay t)
+       (>= (length prefix) company-minimum-prefix-length)))
+
+(defun company-idle-begin ()
+  (and company-mode
+       (not company-candidates)
+       (let ((company-idle-delay t))
+         (company-begin)
+         (company-post-command))))
 
 (defun company-begin ()
   (when company-candidates

commit 4ed29b591ca9128b5e2c21ad335120927bd51366
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 23:09:26 2009 +0100

    Added required prefix length.

diff --git a/company.el b/company.el
index 4c58785..49ffe43 100644
--- a/company.el
+++ b/company.el
@@ -52,6 +52,11 @@
   :group 'company
   :type '(repeat (function :tag "function" nil)))
 
+(defcustom company-minimum-prefix-length 3
+  "*"
+  :group 'company
+  :type '(integer :tag "prefix length"))
+
 ;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defvar company-mode-map
@@ -134,18 +139,24 @@
   (let ((offset (- company-selection display-limit -1)))
     (max offset 0)))
 
+(defsubst company-should-complete (prefix)
+  (>= (length prefix) company-minimum-prefix-length))
+
 (defun company-begin ()
+  (when company-candidates
+    (company-cancel))
   (let ((completion-ignore-case nil) ;; TODO: make this optional
         prefix)
     (dolist (backend company-backends)
       (when (setq prefix (funcall backend 'prefix))
-        (setq company-backend backend
-              company-prefix prefix
-              company-candidates
-              (funcall company-backend 'candidates prefix)
-              company-common (try-completion prefix company-candidates)
-              company-selection 0
-              company-point (point))
+        (when (company-should-complete prefix)
+          (setq company-backend backend
+                company-prefix prefix
+                company-candidates
+                (funcall company-backend 'candidates prefix)
+                company-common (try-completion prefix company-candidates)
+                company-selection 0
+                company-point (point)))
         (return prefix)))
     (unless (and company-candidates
                  (not (eq t company-common)))

commit b56ea0ec153cee4af8a99bc7cdc82512261e8b1d
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 22:23:55 2009 +0100

    Added preview overlay.

diff --git a/company.el b/company.el
index 7dc98e8..4c58785 100644
--- a/company.el
+++ b/company.el
@@ -35,6 +35,18 @@
   :group 'company
   :type 'integer)
 
+(defface company-preview
+  '((t :background "blue4"
+       :foreground "wheat"))
+  "*"
+  :group 'company)
+
+(defface company-preview-common
+  '((t :inherit company-preview
+       :foreground "red"))
+  "*"
+  :group 'company)
+
 (defcustom company-backends '(company-elisp-completion)
   "*"
   :group 'company
@@ -150,6 +162,7 @@
   (company-pseudo-tooltip-hide))
 
 (defun company-pre-command ()
+  (company-preview-hide)
   (company-pseudo-tooltip-hide))
 
 (defun company-post-command ()
@@ -158,7 +171,9 @@
   (when company-candidates
     (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
                                           company-candidates
-                                          company-selection)))
+                                          company-selection)
+    (company-preview-show-at-point (point) company-candidates
+                                   company-selection)))
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -307,5 +322,33 @@
     (delete-overlay company-pseudo-tooltip-overlay)
     (setq company-pseudo-tooltip-overlay nil)))
 
+;;; overlay 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-preview-overlay nil)
+(make-variable-buffer-local 'company-preview-overlay)
+
+(defun company-preview-show-at-point (pos text &optional selection)
+  (company-preview-hide)
+
+  (setq company-preview-overlay (make-overlay pos pos))
+
+  (let ((completion (company-strip-prefix (nth company-selection
+                                               company-candidates))))
+    (and (equal pos (point))
+         (not (equal completion ""))
+         (add-text-properties 0 1 '(cursor t) completion))
+
+    (setq completion (propertize completion 'face 'company-preview))
+    (add-text-properties 0 (- (length company-common) (length company-prefix))
+                         '(face company-preview-common) completion)
+
+    (overlay-put company-preview-overlay 'after-string completion)
+    (overlay-put company-preview-overlay 'window (selected-window))))
+
+(defun company-preview-hide ()
+  (when company-preview-overlay
+    (delete-overlay company-preview-overlay)
+    (setq company-preview-overlay nil)))
+
 (provide 'company)
 ;;; company.el ends here

commit a2ffe78ff54f7cac7f5b90c15c6179b3172ff05b
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 09:48:42 2009 +0100

    Added scrolling.

diff --git a/company.el b/company.el
index a5e5251..7dc98e8 100644
--- a/company.el
+++ b/company.el
@@ -118,6 +118,10 @@
 (defsubst company-strip-prefix (str)
   (substring str (length company-prefix)))
 
+(defsubst company-offset (display-limit)
+  (let ((offset (- company-selection display-limit -1)))
+    (max offset 0)))
+
 (defun company-begin ()
   (let ((completion-ignore-case nil) ;; TODO: make this optional
         prefix)
@@ -269,6 +273,11 @@
   (unless lines (error "No text provided"))
   (save-excursion
 
+    ;; Scroll to offset.
+    (let ((offset (company-offset company-tooltip-limit)))
+      (setq lines (nthcdr offset lines))
+      (decf selection offset))
+
     (setq lines (company-fill-propertize-lines column lines selection))
 
 

commit 13074f54a29f7d8e01bb58e292399738afae2466
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 08:58:19 2009 +0100

    Added common prefix completion and visualization.

diff --git a/company.el b/company.el
index f8bd18e..a5e5251 100644
--- a/company.el
+++ b/company.el
@@ -18,6 +18,18 @@
   "*"
   :group 'company)
 
+(defface company-tooltip-common
+  '((t :inherit company-tooltip
+       :foreground "red"))
+  "*"
+  :group 'company)
+
+(defface company-tooltip-common-selection
+  '((t :inherit company-tooltip-selection
+       :foreground "red"))
+  "*"
+  :group 'company)
+
 (defcustom company-tooltip-limit 10
   "*"
   :group 'company
@@ -35,6 +47,7 @@
     (define-key keymap (kbd "M-n") 'company-select-next)
     (define-key keymap (kbd "M-p") 'company-select-previous)
     (define-key keymap (kbd "M-<return>") 'company-complete-selection)
+    (define-key keymap "\t" 'company-complete-common)
     keymap))
 
 ;;;###autoload
@@ -90,9 +103,15 @@
 (defvar company-candidates nil)
 (make-variable-buffer-local 'company-candidates)
 
+(defvar company-common nil)
+(make-variable-buffer-local 'company-common)
+
 (defvar company-selection 0)
 (make-variable-buffer-local 'company-selection)
 
+(defvar company-selection-changed nil)
+(make-variable-buffer-local 'company-selection-changed)
+
 (defvar company-point nil)
 (make-variable-buffer-local 'company-point)
 
@@ -108,19 +127,21 @@
               company-prefix prefix
               company-candidates
               (funcall company-backend 'candidates prefix)
+              company-common (try-completion prefix company-candidates)
               company-selection 0
               company-point (point))
         (return prefix)))
-    (unless (or (cdr company-candidates)
-                (when company-candidates
-                  (not (equal (car company-candidates) company-prefix))))
+    (unless (and company-candidates
+                 (not (eq t company-common)))
       (company-cancel))))
 
 (defun company-cancel ()
   (setq company-backend nil
         company-prefix nil
         company-candidates nil
+        company-common nil
         company-selection 0
+        company-selection-changed nil
         company-point nil)
   (company-pseudo-tooltip-hide))
 
@@ -140,16 +161,22 @@
 (defun company-select-next ()
   (interactive)
   (setq company-selection (min (1- (length company-candidates))
-                               (1+ company-selection))))
+                               (1+ company-selection))
+        company-selection-changed t))
 
 (defun company-select-previous ()
   (interactive)
-  (setq company-selection (max 0 (1- company-selection))))
+  (setq company-selection (max 0 (1- company-selection))
+        company-selection-changed t))
 
 (defun company-complete-selection ()
   (interactive)
   (insert (company-strip-prefix (nth company-selection company-candidates))))
 
+(defun company-complete-common ()
+  (interactive)
+  (insert (company-strip-prefix company-common)))
+
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defconst company-space-strings-limit 100)
@@ -181,9 +208,16 @@
 
 ;;; propertize
 
-(defun company-fill-propertize (line width face)
+(defun company-fill-propertize (line width selected)
   (setq line (company-safe-substring line 0 width))
-  (add-text-properties 0 width (list 'face face) line)
+  (add-text-properties 0 width
+                       (list 'face (if selected
+                                       'company-tooltip-selection
+                                     'company-tooltip)) line)
+  (add-text-properties 0 (length company-common)
+                       (list 'face (if selected
+                                       'company-tooltip-common-selection
+                                     'company-tooltip-common)) line)
   line)
 
 (defun company-fill-propertize-lines (column lines selection)
@@ -195,10 +229,7 @@
       (setq width (max (length (pop lines-copy)) width)))
     (setq width (min width (- (window-width) column)))
     (dotimes (i len)
-      (push (company-fill-propertize (pop lines) width
-                                     (if (equal i selection)
-                                         'company-tooltip-selection
-                                       'company-tooltip))
+      (push (company-fill-propertize (pop lines) width (equal i selection))
             new))
     (nreverse new)))
 

commit d8ace69668441585144c119ce5a70a8f5bd39300
Author: Nikolaj Schumacher <address@hidden>
Date:   Tue Mar 10 00:17:42 2009 +0100

    Initial import

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c531d98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.elc
diff --git a/company.el b/company.el
new file mode 100644
index 0000000..f8bd18e
--- /dev/null
+++ b/company.el
@@ -0,0 +1,271 @@
+(eval-when-compile (require 'cl))
+
+(defgroup company nil
+  ""
+  :group 'abbrev
+  :group 'convenience
+  :group 'maching)
+
+(defface company-tooltip
+  '((t :background "yellow"
+       :foreground "black"))
+  "*"
+  :group 'company)
+
+(defface company-tooltip-selection
+  '((t :background "orange1"
+       :foreground "black"))
+  "*"
+  :group 'company)
+
+(defcustom company-tooltip-limit 10
+  "*"
+  :group 'company
+  :type 'integer)
+
+(defcustom company-backends '(company-elisp-completion)
+  "*"
+  :group 'company
+  :type '(repeat (function :tag "function" nil)))
+
+;;; mode 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-mode-map
+  (let ((keymap (make-sparse-keymap)))
+    (define-key keymap (kbd "M-n") 'company-select-next)
+    (define-key keymap (kbd "M-p") 'company-select-previous)
+    (define-key keymap (kbd "M-<return>") 'company-complete-selection)
+    keymap))
+
+;;;###autoload
+(define-minor-mode company-mode
+  ""
+  nil " comp" company-mode-map
+  (if company-mode
+      (progn
+        (add-hook 'pre-command-hook 'company-pre-command nil t)
+        (add-hook 'post-command-hook 'company-post-command nil t))
+    (remove-hook 'pre-command-hook 'company-pre-command t)
+    (remove-hook 'post-command-hook 'company-post-command t)
+    (company-cancel)))
+
+;;; backends 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-grab (regexp &optional expression)
+  (when (looking-back regexp)
+    (or (match-string-no-properties (or expression 0)) "")))
+
+(defun company-in-string-or-comment (&optional point)
+  (let ((pos (syntax-ppss)))
+    (or (nth 3 pos) (nth 4 pos) (nth 7 pos))))
+
+;;; elisp
+
+(defvar company-lisp-symbol-regexp
+  "\\_<\\(\\sw\\|\\s_\\)+\\_>\\=")
+
+(defun company-grab-lisp-symbol ()
+  (let ((prefix (or (company-grab company-lisp-symbol-regexp) "")))
+    (unless (and (company-in-string-or-comment (- (point) (length prefix)))
+                 (/= (char-before (- (point) (length prefix))) ?`))
+      prefix)))
+
+(defun company-elisp-completion (command &optional arg &rest ignored)
+  (case command
+    ('prefix (and (eq major-mode 'emacs-lisp-mode)
+                  (company-grab-lisp-symbol)))
+    ('candidates (let ((completion-ignore-case nil))
+                   (all-completions arg obarray
+                                    (lambda (symbol) (or (boundp symbol)
+                                                         (fboundp 
symbol))))))))
+
+;;; completion mechanism 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-backend nil)
+(make-variable-buffer-local 'company-backend)
+
+(defvar company-prefix nil)
+(make-variable-buffer-local 'company-prefix)
+
+(defvar company-candidates nil)
+(make-variable-buffer-local 'company-candidates)
+
+(defvar company-selection 0)
+(make-variable-buffer-local 'company-selection)
+
+(defvar company-point nil)
+(make-variable-buffer-local 'company-point)
+
+(defsubst company-strip-prefix (str)
+  (substring str (length company-prefix)))
+
+(defun company-begin ()
+  (let ((completion-ignore-case nil) ;; TODO: make this optional
+        prefix)
+    (dolist (backend company-backends)
+      (when (setq prefix (funcall backend 'prefix))
+        (setq company-backend backend
+              company-prefix prefix
+              company-candidates
+              (funcall company-backend 'candidates prefix)
+              company-selection 0
+              company-point (point))
+        (return prefix)))
+    (unless (or (cdr company-candidates)
+                (when company-candidates
+                  (not (equal (car company-candidates) company-prefix))))
+      (company-cancel))))
+
+(defun company-cancel ()
+  (setq company-backend nil
+        company-prefix nil
+        company-candidates nil
+        company-selection 0
+        company-point nil)
+  (company-pseudo-tooltip-hide))
+
+(defun company-pre-command ()
+  (company-pseudo-tooltip-hide))
+
+(defun company-post-command ()
+  (unless (equal (point) company-point)
+    (company-begin))
+  (when company-candidates
+    (company-pseudo-tooltip-show-at-point (- (point) (length company-prefix))
+                                          company-candidates
+                                          company-selection)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun company-select-next ()
+  (interactive)
+  (setq company-selection (min (1- (length company-candidates))
+                               (1+ company-selection))))
+
+(defun company-select-previous ()
+  (interactive)
+  (setq company-selection (max 0 (1- company-selection))))
+
+(defun company-complete-selection ()
+  (interactive)
+  (insert (company-strip-prefix (nth company-selection company-candidates))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst company-space-strings-limit 100)
+
+(defconst company-space-strings
+  (let (lst)
+    (dotimes (i company-space-strings-limit)
+      (push (make-string (- company-space-strings-limit 1 i) ?\  ) lst))
+    (apply 'vector lst)))
+
+(defsubst company-space-string (len)
+  (if (< len company-space-strings-limit)
+      (aref company-space-strings len)
+    (make-string len ?\ )))
+
+(defsubst company-safe-substring (str from &optional to)
+  (let ((len (length str)))
+    (if (> from len)
+        ""
+      (if (and to (> to len))
+          (concat (substring str from)
+                  (company-space-string (- to len)))
+        (substring str from to)))))
+
+;;; pseudo-tooltip 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar company-pseudo-tooltip-overlay nil)
+(make-variable-buffer-local 'company-pseudo-tooltip-overlay)
+
+;;; propertize
+
+(defun company-fill-propertize (line width face)
+  (setq line (company-safe-substring line 0 width))
+  (add-text-properties 0 width (list 'face face) line)
+  line)
+
+(defun company-fill-propertize-lines (column lines selection)
+  (let ((width 0)
+        (lines-copy lines)
+        (len (min company-tooltip-limit (length lines)))
+        new)
+    (dotimes (i len)
+      (setq width (max (length (pop lines-copy)) width)))
+    (setq width (min width (- (window-width) column)))
+    (dotimes (i len)
+      (push (company-fill-propertize (pop lines) width
+                                     (if (equal i selection)
+                                         'company-tooltip-selection
+                                       'company-tooltip))
+            new))
+    (nreverse new)))
+
+;;; replace
+
+(defun company-buffer-lines (beg end)
+  (goto-char beg)
+  (let ((row (cdr (posn-col-row (posn-at-point))))
+        lines)
+    (while (< (point) end)
+      (move-to-window-line (incf row))
+      (push (buffer-substring beg (min end (1- (point)))) lines)
+      (setq beg (point)))
+    (nreverse lines)))
+
+(defun company-modify-line (old new offset)
+  (concat (company-safe-substring old 0 offset)
+          new
+          (company-safe-substring old (+ offset (length new)))))
+
+(defun company-modified-substring (beg end lines column)
+  (let ((old (company-buffer-lines beg end))
+        new)
+    ;; Inject into old lines.
+    (while old
+      (push (company-modify-line (pop old) (pop lines) column) new))
+    ;; Append whole new lines.
+    (while lines
+      (push (company-modify-line "" (pop lines) column) new))
+    (concat (mapconcat 'identity (nreverse new) "\n")
+            "\n")))
+
+;; show
+
+(defun company-pseudo-tooltip-show (row column lines &optional selection)
+  (company-pseudo-tooltip-hide)
+  (unless lines (error "No text provided"))
+  (save-excursion
+
+    (setq lines (company-fill-propertize-lines column lines selection))
+
+
+    (move-to-column 0)
+    (move-to-window-line row)
+    (let ((beg (point))
+          (end (save-excursion
+                 (move-to-window-line (min (window-height)
+                                           (+ row company-tooltip-limit)))
+                 (point)))
+          str)
+
+      (setq company-pseudo-tooltip-overlay (make-overlay beg end))
+
+      (overlay-put company-pseudo-tooltip-overlay 'before-string
+                   (company-modified-substring beg end lines column))
+      (overlay-put company-pseudo-tooltip-overlay 'invisible t)
+      (overlay-put company-pseudo-tooltip-overlay 'window (selected-window)))))
+
+(defun company-pseudo-tooltip-show-at-point (pos text &optional selection)
+  (let ((col-row (posn-col-row (posn-at-point pos))))
+    (company-pseudo-tooltip-show (1+ (cdr col-row))
+                                 (car col-row) text selection)))
+
+(defun company-pseudo-tooltip-hide ()
+  (when company-pseudo-tooltip-overlay
+    (delete-overlay company-pseudo-tooltip-overlay)
+    (setq company-pseudo-tooltip-overlay nil)))
+
+(provide 'company)
+;;; company.el ends here

-----------------------------------------------------------------------

Summary of changes:
 admin/archive-contents.el                          |   50 +++---
 admin/update-archive.sh                            |    9 +-
 externals-list                                     |    1 -
 packages/ack/README                                |   34 ----
 packages/ack/README.rst                            |   74 ++++++++
 packages/ack/ack-pkg.el                            |    1 -
 packages/ack/ack.el                                |    2 +-
 packages/coffee-mode/coffee-mode.el                |   13 ++
 packages/company/.dir-locals.el                    |    2 +-
 packages/company/.gitignore                        |    2 +
 packages/company/.travis.yml                       |   32 ++++
 packages/company/Makefile                          |   37 ++++
 packages/company/NEWS.md                           |  179 ++++++++++++++++++++
 packages/company/README                            |    3 -
 packages/company/README.md                         |    4 +
 packages/company/company-pkg.el                    |    1 -
 .../.yas-make-groups => eldoc-eval/README.md}      |    0
 packages/f90-interface-browser/f90-tests.el        |   96 +++++++++++
 packages/ggtags/Makefile                           |   12 ++
 packages/ggtags/README.rst                         |   73 ++++++++
 packages/ioccur/ioccur.el                          |    1 +
 packages/js2-mode/.gitignore                       |    1 +
 packages/js2-mode/.travis.yml                      |   24 +++
 packages/js2-mode/Makefile                         |   26 +++
 packages/js2-mode/README.md                        |   35 ++++
 packages/js2-mode/tests/externs.el                 |   22 +++
 packages/js2-mode/tests/indent.el                  |   75 ++++++++
 packages/js2-mode/tests/parser.el                  |  113 ++++++++++++
 28 files changed, 857 insertions(+), 65 deletions(-)
 delete mode 100644 packages/ack/README
 create mode 100644 packages/ack/README.rst
 delete mode 100644 packages/ack/ack-pkg.el
 create mode 100644 packages/company/.gitignore
 create mode 100644 packages/company/.travis.yml
 create mode 100644 packages/company/Makefile
 create mode 100644 packages/company/NEWS.md
 delete mode 100644 packages/company/README
 create mode 100644 packages/company/README.md
 delete mode 100644 packages/company/company-pkg.el
 copy packages/{yasnippet/snippets/html-mode/.yas-make-groups => 
eldoc-eval/README.md} (100%)
 create mode 100644 packages/f90-interface-browser/f90-tests.el
 create mode 100644 packages/ggtags/Makefile
 create mode 100644 packages/ggtags/README.rst
 create mode 100644 packages/js2-mode/.gitignore
 create mode 100644 packages/js2-mode/.travis.yml
 create mode 100644 packages/js2-mode/Makefile
 create mode 100644 packages/js2-mode/README.md
 create mode 100644 packages/js2-mode/tests/externs.el
 create mode 100644 packages/js2-mode/tests/indent.el
 create mode 100644 packages/js2-mode/tests/parser.el


hooks/post-receive
-- 
ELPA



reply via email to

[Prev in Thread] Current Thread [Next in Thread]