rasp.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "sam.h"
  10. /*
  11. * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,
  12. * so they will be scrolled into visibility in the ~~sam~~ window (yuck!).
  13. */
  14. #define GROWDATASIZE 50 /* if size is > this, send data with grow */
  15. void rcut(List*, Posn, Posn);
  16. int rterm(List*, Posn);
  17. void rgrow(List*, Posn, Posn);
  18. static Posn growpos;
  19. static Posn grown;
  20. static Posn shrinkpos;
  21. static Posn shrunk;
  22. /*
  23. * rasp routines inform the terminal of changes to the file.
  24. *
  25. * a rasp is a list of spans within the file, and an indication
  26. * of whether the terminal knows about the span.
  27. *
  28. * optimize by coalescing multiple updates to the same span
  29. * if it is not known by the terminal.
  30. *
  31. * other possible optimizations: flush terminal's rasp by cut everything,
  32. * insert everything if rasp gets too large.
  33. */
  34. /*
  35. * only called for initial load of file
  36. */
  37. void
  38. raspload(File *f)
  39. {
  40. if(f->rasp == nil)
  41. return;
  42. grown = f->Buffer.nc;
  43. growpos = 0;
  44. if(f->Buffer.nc)
  45. rgrow(f->rasp, 0, f->Buffer.nc);
  46. raspdone(f, 1);
  47. }
  48. void
  49. raspstart(File *f)
  50. {
  51. if(f->rasp == nil)
  52. return;
  53. grown = 0;
  54. shrunk = 0;
  55. outbuffered = 1;
  56. }
  57. void
  58. raspdone(File *f, int toterm)
  59. {
  60. if(f->dot.r.p1 > f->Buffer.nc)
  61. f->dot.r.p1 = f->Buffer.nc;
  62. if(f->dot.r.p2 > f->Buffer.nc)
  63. f->dot.r.p2 = f->Buffer.nc;
  64. if(f->mark.p1 > f->Buffer.nc)
  65. f->mark.p1 = f->Buffer.nc;
  66. if(f->mark.p2 > f->Buffer.nc)
  67. f->mark.p2 = f->Buffer.nc;
  68. if(f->rasp == nil)
  69. return;
  70. if(grown)
  71. outTsll(Hgrow, f->tag, growpos, grown);
  72. else if(shrunk)
  73. outTsll(Hcut, f->tag, shrinkpos, shrunk);
  74. if(toterm)
  75. outTs(Hcheck0, f->tag);
  76. outflush();
  77. outbuffered = 0;
  78. if(f == cmd){
  79. cmdpt += cmdptadv;
  80. cmdptadv = 0;
  81. }
  82. }
  83. void
  84. raspflush(File *f)
  85. {
  86. if(grown){
  87. outTsll(Hgrow, f->tag, growpos, grown);
  88. grown = 0;
  89. }
  90. else if(shrunk){
  91. outTsll(Hcut, f->tag, shrinkpos, shrunk);
  92. shrunk = 0;
  93. }
  94. outflush();
  95. }
  96. void
  97. raspdelete(File *f, uint p1, uint p2, int toterm)
  98. {
  99. long n;
  100. n = p2 - p1;
  101. if(n == 0)
  102. return;
  103. if(p2 <= f->dot.r.p1){
  104. f->dot.r.p1 -= n;
  105. f->dot.r.p2 -= n;
  106. }
  107. if(p2 <= f->mark.p1){
  108. f->mark.p1 -= n;
  109. f->mark.p2 -= n;
  110. }
  111. if(f->rasp == nil)
  112. return;
  113. if(f==cmd && p1<cmdpt){
  114. if(p2 <= cmdpt)
  115. cmdpt -= n;
  116. else
  117. cmdpt = p1;
  118. }
  119. if(toterm){
  120. if(grown){
  121. outTsll(Hgrow, f->tag, growpos, grown);
  122. grown = 0;
  123. }else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){
  124. outTsll(Hcut, f->tag, shrinkpos, shrunk);
  125. shrunk = 0;
  126. }
  127. if(!shrunk || shrinkpos==p2)
  128. shrinkpos = p1;
  129. shrunk += n;
  130. }
  131. rcut(f->rasp, p1, p2);
  132. }
  133. void
  134. raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm)
  135. {
  136. Range r;
  137. if(n == 0)
  138. return;
  139. if(p1 < f->dot.r.p1){
  140. f->dot.r.p1 += n;
  141. f->dot.r.p2 += n;
  142. }
  143. if(p1 < f->mark.p1){
  144. f->mark.p1 += n;
  145. f->mark.p2 += n;
  146. }
  147. if(f->rasp == nil)
  148. return;
  149. if(f==cmd && p1<cmdpt)
  150. cmdpt += n;
  151. if(toterm){
  152. if(shrunk){
  153. outTsll(Hcut, f->tag, shrinkpos, shrunk);
  154. shrunk = 0;
  155. }
  156. if(n>GROWDATASIZE || !rterm(f->rasp, p1)){
  157. rgrow(f->rasp, p1, n);
  158. if(grown && growpos+grown!=p1 && growpos!=p1){
  159. outTsll(Hgrow, f->tag, growpos, grown);
  160. grown = 0;
  161. }
  162. if(!grown)
  163. growpos = p1;
  164. grown += n;
  165. }else{
  166. if(grown){
  167. outTsll(Hgrow, f->tag, growpos, grown);
  168. grown = 0;
  169. }
  170. rgrow(f->rasp, p1, n);
  171. r = rdata(f->rasp, p1, n);
  172. if(r.p1!=p1 || r.p2!=p1+n)
  173. panic("rdata in toterminal");
  174. outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n));
  175. }
  176. }else{
  177. rgrow(f->rasp, p1, n);
  178. r = rdata(f->rasp, p1, n);
  179. if(r.p1!=p1 || r.p2!=p1+n)
  180. panic("rdata in toterminal");
  181. }
  182. }
  183. #define M 0x80000000L
  184. #define P(i) r->posnptr[i]
  185. #define T(i) (P(i)&M) /* in terminal */
  186. #define L(i) (P(i)&~M) /* length of this piece */
  187. void
  188. rcut(List *r, Posn p1, Posn p2)
  189. {
  190. Posn p, x;
  191. int i;
  192. if(p1 == p2)
  193. panic("rcut 0");
  194. for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
  195. ;
  196. if(i == r->nused)
  197. panic("rcut 1");
  198. if(p < p1){ /* chop this piece */
  199. if(p+L(i) < p2){
  200. x = p1-p;
  201. p += L(i);
  202. }else{
  203. x = L(i)-(p2-p1);
  204. p = p2;
  205. }
  206. if(T(i))
  207. P(i) = x|M;
  208. else
  209. P(i) = x;
  210. i++;
  211. }
  212. while(i<r->nused && p+L(i)<=p2){
  213. p += L(i);
  214. dellist(r, i);
  215. }
  216. if(p < p2){
  217. if(i == r->nused)
  218. panic("rcut 2");
  219. x = L(i)-(p2-p);
  220. if(T(i))
  221. P(i) = x|M;
  222. else
  223. P(i) = x;
  224. }
  225. /* can we merge i and i-1 ? */
  226. if(i>0 && i<r->nused && T(i-1)==T(i)){
  227. x = L(i-1)+L(i);
  228. dellist(r, i--);
  229. if(T(i))
  230. P(i)=x|M;
  231. else
  232. P(i)=x;
  233. }
  234. }
  235. void
  236. rgrow(List *r, Posn p1, Posn n)
  237. {
  238. Posn p;
  239. int i;
  240. if(n == 0)
  241. panic("rgrow 0");
  242. for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))
  243. ;
  244. if(i == r->nused){ /* stick on end of file */
  245. if(p!=p1)
  246. panic("rgrow 1");
  247. if(i>0 && !T(i-1))
  248. P(i-1)+=n;
  249. else
  250. inslist(r, i, n);
  251. }else if(!T(i)) /* goes in this empty piece */
  252. P(i)+=n;
  253. else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */
  254. P(i-1)+=n;
  255. else if(p==p1)
  256. inslist(r, i, n);
  257. else{ /* must break piece in terminal */
  258. inslist(r, i+1, (L(i)-(p1-p))|M);
  259. inslist(r, i+1, n);
  260. P(i) = (p1-p)|M;
  261. }
  262. }
  263. int
  264. rterm(List *r, Posn p1)
  265. {
  266. Posn p;
  267. int i;
  268. for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
  269. ;
  270. if(i==r->nused && (i==0 || !T(i-1)))
  271. return 0;
  272. return T(i);
  273. }
  274. Range
  275. rdata(List *r, Posn p1, Posn n)
  276. {
  277. Posn p;
  278. int i;
  279. Range rg;
  280. if(n==0)
  281. panic("rdata 0");
  282. for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))
  283. ;
  284. if(i==r->nused)
  285. panic("rdata 1");
  286. if(T(i)){
  287. n-=L(i)-(p1-p);
  288. if(n<=0){
  289. rg.p1 = rg.p2 = p1;
  290. return rg;
  291. }
  292. p+=L(i++);
  293. p1 = p;
  294. }
  295. if(T(i) || i==r->nused)
  296. panic("rdata 2");
  297. if(p+L(i)<p1+n)
  298. n = L(i)-(p1-p);
  299. rg.p1 = p1;
  300. rg.p2 = p1+n;
  301. if(p!=p1){
  302. inslist(r, i+1, L(i)-(p1-p));
  303. P(i)=p1-p;
  304. i++;
  305. }
  306. if(L(i)!=n){
  307. inslist(r, i+1, L(i)-n);
  308. P(i)=n;
  309. }
  310. P(i)|=M;
  311. /* now i is set; can we merge? */
  312. if(i<r->nused-1 && T(i+1)){
  313. P(i)=(n+=L(i+1))|M;
  314. dellist(r, i+1);
  315. }
  316. if(i>0 && T(i-1)){
  317. P(i)=(n+L(i-1))|M;
  318. dellist(r, i-1);
  319. }
  320. return rg;
  321. }