Asked by @privat because friendz's app played multiple musics when pausing/resuming the app
Pull-Request: #1721
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
import solver
import mnit::tileset
import app::data_store
-import md5
intrude import grid
intrude import level
self.over = self.level.fullname
if self.level.get_state >= l.l_won then
- if game.levels[9].get_state >= l.l_won then self.over += " --- {self.level.score}/{self.level.par}"
+ if game.levels[9].get_state >= l.l_won then self.over += " --- {self.level.score}/{self.level.gold}"
else if self.level.get_state >= l.l_open then
- if game.levels[9].get_state >= l.l_open then self.over += " --- ?/{self.level.par}"
+ if game.levels[9].get_state >= l.l_open then self.over += " --- ?/{self.level.gold}"
end
- #self.enabled = l.get_state >= l.l_open
+ self.enabled = l.get_state >= l.l_open or game.cheated
end
redef fun draw(ctx)
end
ctx.blit(game.img[ix,iy], self.x, self.y)
- if s == l.l_par then
+ if s == l.l_gold then
ctx.blit(game.img2[7,0], self.x + bw*5/8, self.y-bh*1/8)
end
ctx.textx(self.level.name, self.x+5, self.y+5, 24, null, null)
end
if game.levels[9].get_state >= level.l_won then
if level.is_challenge then
- ctx.textx("GOAL: {level.par}",self.x,self.y+44,21,"yellow",null)
+ ctx.textx("GOAL: {level.gold}",self.x,self.y+44,21,"yellow",null)
else
- ctx.textx("PAR: {level.par}",self.x,self.y+44,21,"yellow",null)
+ ctx.textx("GOLD: {level.gold}",self.x,self.y+44,21,"yellow",null)
end
end
end
do
print "***STATUS** {txt}"
self.tmp_txt = txt
- self.tmp_txt_ttl = 20
+ self.tmp_txt_ttl = 60
self.tmp_txt_color = color
end
# Font
var font = new TileSetFont(app.load_image("deltaforce_font.png"), 16, 17, "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789.:;!?\"'() -,/")
- var xxx = """
- fun save_cookie(name, val:String) do
- var days = 365
- var date = new Date()
- date.setTime(date.getTime()+(days*24*60*60*1000))
- document.cookie = name+"="+val+"; expires="+date.toGMTString()+"; path=/"
- end
-
- fun read_cookie(name:String):String do
- var key = name + "="
- var ca = document.cookie.split(';')
- for(var i=0; i<ca.length; i++) do
- var c = ca[i]
- while (c[0]==' ') c = c.substring(1, c.length)
- if (c.indexOf(key) == 0) return c.substring(key.length)
- end
- return null
- end
- """
-
# DISPLAY *****************************************************************
# Is the game in editing mode
# SOUND
# Is the music muted?
- var music_muted: Bool = false #read_cookie("music_muted")
+ var music_muted: Bool = app.data_store["music_muted"] == true
# Is the sound effects muted?
- var sfx_muted: Bool = false #read_cookie("sfx_muted")
+ var sfx_muted: Bool = app.data_store["sfx_muted"] == true
# The background music resource. */
var music = new Music("music.ogg")
# ResizeButton
var button_size = new ResizeButton(self)
+ # Cheat mode enabled?
+ var cheated = false
+
init
do
- load_levels
init_buttons
entities.clear
title
+
+ if not music_muted then music.play
end
# fill `buttons`
# Play a level in player mode.
fun play(l: Level)
do
+ save # save the previous level grid
level = l
- grid.load(level.str)
+ grid.load(level.saved_str or else level.str)
init_play_menu(false)
if level.status != "" then
statusbar.main_txt = level.status
# Helper function to initialize the menu (and tile) screen
fun init_menu
do
+ save # save the previous level grid
init_game
level = null
var i = levels.first
end
t = new Achievement(self, 0, "Training")
entities.push(t)
- t = new Achievement(self, 1, "Par")
+ t = new Achievement(self, 1, "Gold")
entities.push(t)
t = new Achievement(self, 2, "Editor")
entities.push(t)
fun onKeyDown(ev: Event) do
var kc = ev.char_code
if kc == "e" then
+ set_tmp("RUN EDITOR")
grid_edit = grid.copy(true)
edit_grid(grid)
+ else if kc == "c" then
+ if cheated then
+ set_tmp("CHEAT: OFF")
+ snd_duh.play
+ cheated = false
+ else
+ set_tmp("CHEAT: ON")
+ snd_win.play
+ cheated = true
+ end
else if kc == "s" then
if solver == null then
solver = (new FriendzProblem(grid)).solve
else
solver_pause = not solver_pause
end
+ if solver_pause then
+ set_tmp("SOLVER: PAUSED")
+ else
+ set_tmp("SOLVER: ON")
+ end
#solver.step
else if kc == "d" then
if solver == null then
solver = (new FriendzProblem(grid)).solve
solver_pause = true
+ set_tmp("SOLVER: ON")
else
+ solver_pause = true
solver.run_steps(1)
+ set_tmp("SOLVER: ONE STEP")
end
else if kc == "+" then
solver_steps += 100
- print solver_steps
+ set_tmp("SOLVER: {solver_steps} STEPS")
else if kc == "-" then
solver_steps -= 100
- print solver_steps
+ set_tmp("SOLVER: {solver_steps} STEPS")
else for g in entities do
if kc == g.shortcut then
g.click(ev)
end
end
+ fun set_tmp(s: String)
+ do
+ statusbar.set_tmp(s, "cyan")
+ end
+
redef fun load_levels
do
super
for level in levels do
- var score = app.data_store["s{level.str.md5}"]
+ var score = app.data_store["s{level.str}"]
if score isa Int then
level.score = score
end
+ var saved_str = app.data_store["g{level.str}"]
+ if saved_str isa String then
+ print "LOAD {level.name}: {saved_str}"
+ level.saved_str = saved_str
+ end
+ end
+ end
+
+ fun save
+ do
+ var l = level
+ if l != null then
+ l.save
end
end
end
init(game: Game)
do
super(game, "MUSIC", 470, 412, "purple", "Mute the music", "Unmute the music")
+ toggled = game.music_muted
end
redef fun click2(ev)
do
game.music_muted = self.toggled
if game.music_muted then game.music.pause else game.music.play
- #game.save_cookie("music_muted",music_muted?"true":"")
+ app.data_store["music_muted"] = game.music_muted
end
end
init(game: Game)
do
super(game, "SOUND FX", 470, 382, "purple", "Mute the sound effects", "Unmute the sound effects")
+ toggled = game.sfx_muted
end
redef fun click2(ev)
do
game.sfx_muted = self.toggled
if not game.sfx_muted then game.snd_whip.play # Because the automatic one was muted
- #save_cookie("sfx_muted",sfx_muted?"true":"")
+ app.data_store["sfx_muted"] = game.sfx_muted
end
end
# img loading?
end
+ redef fun on_pause
+ do
+ super
+ game.save
+ end
+
# Maximum wanted frame per second
var max_fps = 30
end
redef class Level
- redef fun save
+ # Save the score and grid of the level
+ fun save
do
- app.data_store["s{str.md5}"] = if score > 0 then score else null
+ app.data_store["s{str}"] = if score > 0 then score else null
+ var saved = game.grid.save
+ saved_str = saved
+ app.data_store["g{str}"] = saved
+ print "SAVE: {name}: {saved}"
end
+
+ # The saved player grid (to continue games)
+ var saved_str: nullable String = null
end
fun save: String
do
var res = ""
- var str = ".#ABCDEFGHI"
+ var str = ".abcdefghi#ABCDEFGHI"
for y in [0..height[ do
var rle = 0
var last: nullable Int = null
for x in [0..width[ do
var t = self.grid[x][y]
- var tk = 0
- if t.fixed then tk = t.kind + 1
+ var tk = t.kind
+ if t.fixed then tk += 10
if tk == last and rle<9 then
rle += 1
else
x += 1
else if c == '#' then
var t = self.get(x,y)
+ assert t != null
t.fixed = true
x += 1
else if c >= 'A' and c <= 'I' then
t.update(c.ascii-'A'.ascii+1)
t.fixed = true
x += 1
+ else if c >= 'a' and c <= 'i' then
+ var t = self.get(x,y)
+ assert t != null
+ t.update(c.ascii-'a'.ascii+1)
+ x += 1
else if c >= '1' and c <= '9' then
rle = c.to_i
else
if x>0 then y += 1
if x > mx then mx = x
if y > my then my = y
- if mx<3 or my<3 or mx>=max_width or my>=max_height then
+ if mx<3 or my<3 or mx>max_width or my>max_height then
return false
end
self.resize(mx,my)
var ls = code.split(";")
self.number = i
self.str = ls[0]
- self.par = ls[1].to_i
+ self.gold = ls[1].to_i
if ls.length >= 3 then
self.status = ls[2]
end
# initial grid position
var str: String
- # top score
- var par: Int
+ # top score to get gold
+ var gold: Int
# Help message if any
var status: String = ""
var l_disabled = 1
var l_open = 2
var l_won = 3
- var l_par = 4
+ var l_gold = 4
fun get_state: Int
do
if self.score == 0 then
if self.number == 0 or game.levels[self.number-1].score > 0 then return l_open
if self.number == 25 and game.levels[19].score > 0 then return l_open else return l_disabled
- else if self.score < self.par or not game.levels[9].score > 0 then
+ else if self.score < self.gold or not game.levels[9].score > 0 then
return l_won
- else return l_par
+ else return l_gold
end
# Returns true if g is a wining condition for the level.
fun check_won(g: Grid): Bool
do
- var w = g.won and (not self.is_challenge or g.number >= self.par)
+ var w = g.won and (not self.is_challenge or g.number >= self.gold)
if not w then return false
if g.number > self.score then
self.score = g.number
- self.save
end
return true
end
-
- # Save the score of the level
- fun save do end
end
# main game object
module opportunity_controller
import nitcorn
-import sha1
import templates
import opportunity_model
redef fun commit(db) do
if id == "" then
var time = get_time
- var tmpid = (name + date + place + time.to_s).sha1_to_s
+ var tmpid = (name + date + place + time.to_s).sha1.hexdigest
if not db.execute("INSERT INTO meetups (id, name, date, place, answer_mode) VALUES({tmpid.to_sql_string}, {name.html_escape.to_sql_string}, {date.html_escape.to_sql_string}, {place.html_escape.to_sql_string}, {answer_mode});") then
print "Error recording entry Meetup {self}"
print db.error or else "Null error"
import sha1
-print "Rosetta Code".sha1_to_s
+print "Rosetta Code".sha1.hexdigest
# Offers the base 64 encoding and decoding algorithms
module base64
-redef class String
-
+redef class NativeString
# Alphabet used by the base64 algorithm
- private fun base64_chars : String
+ private fun base64_chars : SequenceRead[Byte]
do
- return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes
end
+
+ # Reversed alphabet for base64
private fun inverted_base64_chars : HashMap[Byte, Byte]
do
var inv_base64_chars = new HashMap[Byte, Byte]
- for k in [0..base64_chars.bytelen[ do
- inv_base64_chars[base64_chars.bytes[k]] = k.to_b
+ var l = base64_chars.length
+ for k in [0 .. l[ do
+ inv_base64_chars[base64_chars[k]] = k.to_b
end
return inv_base64_chars
end
- # Encodes the receiver string to base64.
+ # Encodes `self` to base64.
+ #
# By default, uses "=" for padding.
- fun encode_base64 : String do return encode_base64_custom_padding('='.ascii.to_b)
-
- # Encodes the receiver string to base64 using a custom padding character.
#
- # If using the default padding character `=`, see `encode_base64`.
- fun encode_base64_custom_padding(padding : Byte) : String
- do
- var base64_bytes = once base64_chars.bytes
- var length = bytelen
-
+ # assert "string".encode_base64 == "c3RyaW5n"
+ private fun encode_base64(length: Int, padding: nullable Byte): Bytes do
+ var base64_bytes = once base64_chars
+ if padding == null then padding = '='.ascii.to_b
var steps = length / 3
var bytes_in_last_step = length % 3
var result_length = steps * 4
if bytes_in_last_step > 0 then result_length += 4
- var result = new NativeString(result_length + 1)
- var bytes = self.bytes
- result[result_length] = 0u8
-
- var mask_6bit = 0b0011_1111
+ var result = new Bytes.with_capacity(result_length)
+ var in_off = 0
for s in [0 .. steps[ do
- var e = 0
- for ss in [0 .. 3[ do
- e += bytes[s * 3 + ss].to_i << ((2 - ss) * 8)
- end
- for ss in [0..4[ do
- result[s * 4 + 3 - ss] = base64_bytes[(e >> (ss * 6)) & mask_6bit]
- end
+ var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i
+ result.add base64_bytes[ind]
+ ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i
+ result.add base64_bytes[ind]
+ ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i
+ result.add base64_bytes[ind]
+ ind = (self[in_off + 2] & 0b0011_1111u8).to_i
+ result.add base64_bytes[ind]
+ in_off += 3
end
-
- var out_off = result_length - 4
- var in_off = length - bytes_in_last_step
if bytes_in_last_step == 1 then
- result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
- result[out_off + 1] = base64_bytes[((bytes[in_off] & 0b0000_0011u8) << 4).to_i]
- out_off += 2
+ result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+ result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i]
else if bytes_in_last_step == 2 then
- result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
- result[out_off + 1] = base64_bytes[(((bytes[in_off] & 0b0000_0011u8) << 4) | ((bytes[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
- result[out_off + 2] = base64_bytes[((bytes[in_off + 1] & 0b0000_1111u8) << 2).to_i]
- out_off += 3
- end
- if bytes_in_last_step > 0 then
- for i in [out_off .. result_length[ do result[i] = padding
+ result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+ result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
+ result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i]
end
+ var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0
+ for i in [0 .. rempad[ do result.add padding
- return result.to_s_with_length(result_length)
+ return result
end
- # Decodes the receiver string from base64.
- # By default, uses "=" for padding.
- fun decode_base64 : String do return decode_base64_custom_padding('='.ascii.to_b)
-
- # Decodes the receiver string to base64 using a custom padding character.
+ # Decodes `self` from base64
#
- # If using the default padding character `=`, see `decode_base64`.
- fun decode_base64_custom_padding(padding : Byte) : String
- do
+ # assert "c3RyaW5n".decode_base64 == "string"
+ #
+ # REQUIRE: `length % 4 == 0`
+ private fun decode_base64(length: Int, padding: nullable Byte): Bytes do
+ if padding == null then padding = '='.ascii.to_b
var inv = once inverted_base64_chars
- var length = bytelen
- if length == 0 then return ""
+ if length == 0 then return new Bytes.empty
assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4"
- var bytes = self.bytes
+ var bytes = self
var steps = length / 4
var result_length = steps * 3
if padding_len == 1 then result_length -= 1
if padding_len == 2 then result_length -= 2
- var result = new NativeString(result_length + 1)
- result[result_length] = 0u8
+ var result = new Bytes.with_capacity(result_length + 1)
for s in [0 .. steps[ do
var c0 = inv[bytes[s * 4]]
var c1 = inv[bytes[s * 4 + 1]]
var c2 = inv[bytes[s * 4 + 2]]
var c3 = inv[bytes[s * 4 + 3]]
- result[s * 3] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
- result[s * 3 + 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
- result[s * 3 + 2] = ((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+ result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
+ result.add (((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8))
end
var last_start = steps * 4
var c0 = inv[bytes[last_start]]
var c1 = inv[bytes[last_start + 1]]
var c2 = inv[bytes[last_start + 2]]
- result[result_length - 2] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
- result[result_length - 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+ result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
else if padding_len == 2 then
var c0 = inv[bytes[last_start]]
var c1 = inv[bytes[last_start + 1]]
- result[result_length - 1] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
end
- return result.to_s_with_length(result_length)
+ return result
+ end
+end
+
+redef class Bytes
+
+ # Encodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `encode_base64`.
+ fun encode_base64(padding: nullable Byte): Bytes
+ do
+ return items.encode_base64(length, padding)
+ end
+
+ # Decodes the receiver string to base64 using a custom padding character.
+ #
+ # Default padding character `=`
+ fun decode_base64(padding : nullable Byte) : Bytes
+ do
+ return items.decode_base64(length, padding)
+ end
+end
+
+redef class String
+
+ # Encodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `encode_base64`.
+ fun encode_base64(padding: nullable Byte): String
+ do
+ return to_cstring.encode_base64(bytelen, padding).to_s
+ end
+
+ # Decodes the receiver string to base64 using a custom padding character.
+ #
+ # Default padding character `=`
+ fun decode_base64(padding : nullable Byte) : String
+ do
+ return to_cstring.decode_base64(bytelen, padding).to_s
end
end
import collection::array
intrude import text::flat
+redef class Byte
+ # Write self as a string into `ns` at position `pos`
+ private fun add_digest_at(ns: NativeString, pos: Int) do
+ var tmp = (0xF0u8 & self) >> 4
+ ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+ tmp = 0x0Fu8 & self
+ ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+ end
+
+ # Is `self` a valid hexadecimal digit (in ASCII)
+ #
+ # ~~~nit
+ # intrude import core::bytes
+ # assert not '/'.ascii.to_b.is_valid_hexdigit
+ # assert '0'.ascii.to_b.is_valid_hexdigit
+ # assert '9'.ascii.to_b.is_valid_hexdigit
+ # assert not ':'.ascii.to_b.is_valid_hexdigit
+ # assert not '@'.ascii.to_b.is_valid_hexdigit
+ # assert 'A'.ascii.to_b.is_valid_hexdigit
+ # assert 'F'.ascii.to_b.is_valid_hexdigit
+ # assert not 'G'.ascii.to_b.is_valid_hexdigit
+ # assert not '`'.ascii.to_b.is_valid_hexdigit
+ # assert 'a'.ascii.to_b.is_valid_hexdigit
+ # assert 'f'.ascii.to_b.is_valid_hexdigit
+ # assert not 'g'.ascii.to_b.is_valid_hexdigit
+ # ~~~
+ private fun is_valid_hexdigit: Bool do
+ return (self >= 0x30u8 and self <= 0x39u8) or
+ (self >= 0x41u8 and self <= 0x46u8) or
+ (self >= 0x61u8 and self <= 0x66u8)
+ end
+
+ # `self` as a hexdigit to its byte value
+ #
+ # ~~~nit
+ # intrude import core::bytes
+ # assert 0x39u8.hexdigit_to_byteval == 0x09u8
+ # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8
+ # ~~~
+ #
+ # REQUIRE: `self.is_valid_hexdigit`
+ private fun hexdigit_to_byteval: Byte do
+ if self >= 0x30u8 and self <= 0x39u8 then
+ return self - 0x30u8
+ else if self >= 0x41u8 and self <= 0x46u8 then
+ return self - 0x37u8
+ else if self >= 0x61u8 and self <= 0x66u8 then
+ return self - 0x57u8
+ end
+ # Happens only if the requirement is not met.
+ # i.e. this abort is here to please the compiler
+ abort
+ end
+end
+
# A buffer containing Byte-manipulation facilities
#
# Uses Copy-On-Write when persisted
super AbstractArray[Byte]
# A NativeString being a char*, it can be used as underlying representation here.
- private var items: NativeString
+ var items: NativeString
# Number of bytes in the array
redef var length
return items[i]
end
+ # Returns self as a hexadecimal digest
+ fun hexdigest: String do
+ var elen = length * 2
+ var ns = new NativeString(elen)
+ var i = 0
+ var oi = 0
+ while i < length do
+ self[i].add_digest_at(ns, oi)
+ i += 1
+ oi += 2
+ end
+ return new FlatString.full(ns, elen, 0, elen - 1, elen)
+ end
+
# var b = new Bytes.with_capacity(1)
# b[0] = 101u8
# assert b.to_s == "e"
redef fun to_s do
persisted = true
var b = self
- if not is_utf8 then
- b = clean_utf8
- persisted = false
- end
- return new FlatString.with_infos(b.items, b.length, 0, b.length -1)
+ var r = b.items.to_s_with_length(length)
+ if r != items then persisted = false
+ return r
end
redef fun iterator do return new BytesIterator.with_buffer(self)
- # Is the byte collection valid UTF-8 ?
- fun is_utf8: Bool do
- var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
- var lobounds = once [0, 0x80, 0x800, 0x10000]
- var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
- var pos = 0
- var len = length
- var mits = items
- while pos < len do
- var nxst = mits.length_of_char_at(pos)
- var charst_index = (nxst - 1) * 2
- if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
- var c = mits.char_at(pos)
- var cp = c.ascii
- if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
- if cp >= 0xD800 and cp <= 0xDFFF or
- cp == 0xFFFE or cp == 0xFFFF then return false
- else
- return false
- end
- else
- return false
- end
- pos += nxst
- end
- return true
- end
-
- # Cleans the bytes of `self` to be UTF-8 compliant
- private fun clean_utf8: Bytes do
- var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
- var badchar = once [0xEFu8, 0xBFu8, 0xBDu8]
- var lobounds = once [0, 0x80, 0x800, 0x10000]
- var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
- var pos = 0
- var len = length
- var ret = new Bytes.with_capacity(len)
- var mits = items
- while pos < len do
- var nxst = mits.length_of_char_at(pos)
- var charst_index = (nxst - 1) * 2
- if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
- var c = mits.char_at(pos)
- var cp = c.ascii
- if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
- if cp >= 0xD800 and cp <= 0xDFFF or
- cp == 0xFFFE or cp == 0xFFFF then
- ret.append badchar
- pos += 1
- else
- var pend = pos + nxst
- for i in [pos .. pend[ do ret.add mits[i]
- pos += nxst
- end
- else
- ret.append badchar
- pos += 1
- end
- else
- ret.append badchar
- pos += 1
- end
- end
- return ret
- end
end
private class BytesIterator
var max: Int
- init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1)
+ init with_buffer(b: Bytes) do init(b.items, 0, b.length)
redef fun is_ok do return index < max
return b
end
+ # Is `self` a valid hexdigest ?
+ #
+ # assert "0B1d3F".is_valid_hexdigest
+ # assert not "5G".is_valid_hexdigest
+ fun is_valid_hexdigest: Bool do
+ for i in bytes do if not i.is_valid_hexdigit then return false
+ return true
+ end
+
# Appends `self.bytes` to `b`
fun append_to_bytes(b: Bytes) do
for s in substrings do
b.append_ns_from(s.items, s.bytelen, from)
end
end
+
+ # Returns a new `Bytes` instance with the digest as content
+ #
+ # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8]
+ #
+ # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0
+ fun hexdigest_to_bytes: Bytes do
+ var b = bytes
+ var pos = 0
+ var max = bytelen
+ var ret = new Bytes.with_capacity(max / 2)
+ while pos < max do
+ ret.add((b[pos].hexdigit_to_byteval << 4) |
+ b[pos + 1].hexdigit_to_byteval)
+ pos += 2
+ end
+ return ret
+ end
end
redef class FlatText
# ~~~
fun read_all: String do
var s = read_all_bytes
- if not s.is_utf8 then s = s.clean_utf8
var slen = s.length
if slen == 0 then return ""
var rets = ""
var pos = 0
- var sits = s.items
+ var str = s.items.clean_utf8(slen)
+ slen = str.bytelen
+ var sits = str.items
var remsp = slen
while pos < slen do
# The 129 size was decided more or less arbitrarily
redef fun to_s_with_length(length): FlatString
do
assert length >= 0
- var str = new FlatString.with_infos(self, length, 0, length - 1)
- return str
+ return clean_utf8(length)
end
redef fun to_s_full(bytelen, unilen) do
redef fun to_s_with_copy: FlatString
do
var length = cstring_length
+ var r = clean_utf8(length)
+ if r.items != self then return r
var new_self = new NativeString(length + 1)
copy_to(new_self, length, 0, 0)
var str = new FlatString.with_infos(new_self, length, 0, length - 1)
return str
end
+ # Cleans a NativeString if necessary
+ fun clean_utf8(len: Int): FlatString do
+ var replacements: nullable Array[Int] = null
+ var end_length = len
+ var pos = 0
+ var chr_ln = 0
+ while pos < len do
+ var b = self[pos]
+ var nxst = length_of_char_at(pos)
+ var ok_st: Bool
+ if nxst == 1 then
+ ok_st = b & 0x80u8 == 0u8
+ else if nxst == 2 then
+ ok_st = b & 0xE0u8 == 0xC0u8
+ else if nxst == 3 then
+ ok_st = b & 0xF0u8 == 0xE0u8
+ else
+ ok_st = b & 0xF8u8 == 0xF0u8
+ end
+ if not ok_st then
+ if replacements == null then replacements = new Array[Int]
+ replacements.add pos
+ end_length += 2
+ pos += 1
+ chr_ln += 1
+ continue
+ end
+ var ok_c: Bool
+ var c = char_at(pos)
+ var cp = c.ascii
+ if nxst == 1 then
+ ok_c = cp >= 0 and cp <= 0x7F
+ else if nxst == 2 then
+ ok_c = cp >= 0x80 and cp <= 0x7FF
+ else if nxst == 3 then
+ ok_c = cp >= 0x800 and cp <= 0xFFFF
+ ok_c = ok_c and not (cp >= 0xD800 and cp <= 0xDFFF) and cp != 0xFFFE and cp != 0xFFFF
+ else
+ ok_c = cp >= 0x10000 and cp <= 0x10FFFF
+ end
+ if not ok_c then
+ if replacements == null then replacements = new Array[Int]
+ replacements.add pos
+ end_length += 2
+ pos += 1
+ chr_ln += 1
+ continue
+ end
+ pos += c.u8char_len
+ chr_ln += 1
+ end
+ var ret = self
+ if end_length != len then
+ ret = new NativeString(end_length)
+ var old_repl = 0
+ var off = 0
+ var repls = replacements.as(not null)
+ var r = repls.items.as(not null)
+ var imax = repls.length
+ for i in [0 .. imax[ do
+ var repl_pos = r[i]
+ var chkln = repl_pos - old_repl
+ copy_to(ret, chkln, old_repl, off)
+ off += chkln
+ ret[off] = 0xEFu8
+ ret[off + 1] = 0xBFu8
+ ret[off + 2] = 0xBDu8
+ old_repl = repl_pos + 1
+ off += 3
+ end
+ copy_to(ret, len - old_repl, old_repl, off)
+ end
+ return new FlatString.full(ret, end_length, 0, end_length - 1, chr_ln)
+ end
+
# Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
#
# Very unsafe, make sure to have room for this char prior to calling this function.
end
i += 1
end
- return ns.to_s_with_length(sl)
+ return new FlatString.with_infos(ns, sl, 0, sl - 1)
end
end
end
i += 1
end
- return ns.to_s_with_length(sl)
+ return new FlatString.with_infos(ns, sl, 0, sl - 1)
end
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services for matrices of `Float` values
+module matrix
+
+# A rectangular array of `Float`
+#
+# Require: `width > 0 and height > 0`
+class Matrix
+ super Cloneable
+
+ # Number of columns
+ var width: Int
+
+ # Number of rows
+ var height: Int
+
+ # Items of this matrix, rows by rows
+ private var items: Array[Float] is lazy do
+ return new Array[Float].filled_with(0.0, width*height)
+ end
+
+ # Create a matrix from nested sequences
+ #
+ # Require: all rows are of the same length
+ #
+ # ~~~
+ # var matrix = new Matrix.from([[1.0, 2.0],
+ # [3.0, 4.0]])
+ # assert matrix.to_s == """
+ # 1.0 2.0
+ # 3.0 4.0"""
+ # ~~~
+ init from(items: SequenceRead[SequenceRead[Float]])
+ do
+ if items.is_empty then
+ init(0, 0)
+ return
+ end
+
+ init(items.first.length, items.length)
+
+ for j in height.times do assert items[j].length == width
+
+ for j in height.times do
+ for i in width.times do
+ self[j, i] = items[j][i]
+ end
+ end
+ end
+
+ # Get each row of this matrix in nested arrays
+ #
+ # ~~~
+ # var items = [[1.0, 2.0],
+ # [3.0, 4.0]]
+ # var matrix = new Matrix.from(items)
+ # assert matrix.to_a == items
+ # ~~~
+ fun to_a: Array[Array[Float]]
+ do
+ var a = new Array[Array[Float]]
+ for j in height.times do
+ var row = new Array[Float]
+ for i in width.times do
+ row.add self[j, i]
+ end
+ a.add row
+ end
+ return a
+ end
+
+ # Create a matrix from an `Array[Float]` composed of rows after rows
+ #
+ # Require: `width > 0 and height > 0`
+ # Require: `array.length >= width*height`
+ #
+ # ~~~
+ # var matrix = new Matrix.from_array(2, 2, [1.0, 2.0,
+ # 3.0, 4.0])
+ # assert matrix.to_s == """
+ # 1.0 2.0
+ # 3.0 4.0"""
+ # ~~~
+ init from_array(width, height: Int, array: SequenceRead[Float])
+ do
+ assert width > 0
+ assert height > 0
+ assert array.length >= width*height
+
+ init(width, height)
+
+ for i in height.times do
+ for j in width.times do
+ self[j, i] = array[i + j*width]
+ end
+ end
+ end
+
+ # Create an identity matrix
+ #
+ # Require: `size >= 0`
+ #
+ # ~~~
+ # var i = new Matrix.identity(3)
+ # assert i.to_s == """
+ # 1.0 0.0 0.0
+ # 0.0 1.0 0.0
+ # 0.0 0.0 1.0"""
+ # ~~~
+ new identity(size: Int)
+ do
+ assert size >= 0
+
+ var matrix = new Matrix(size, size)
+ for i in size.times do
+ for j in size.times do
+ matrix[j, i] = if i == j then 1.0 else 0.0
+ end
+ end
+ return matrix
+ end
+
+ # Create a new clone of this matrix
+ redef fun clone do return new Matrix.from_array(width, height, items.clone)
+
+ # Get the value at column `y` and row `x`
+ #
+ # Require: `x >= 0 and x <= width and y >= 0 and y <= height`
+ #
+ # ~~~
+ # var matrix = new Matrix.from([[0.0, 0.1],
+ # [1.0, 1.1]])
+ #
+ # assert matrix[0, 0] == 0.0
+ # assert matrix[0, 1] == 0.1
+ # assert matrix[1, 0] == 1.0
+ # assert matrix[1, 1] == 1.1
+ # ~~~
+ fun [](y, x: Int): Float
+ do
+ assert x >= 0 and x < width
+ assert y >= 0 and y < height
+
+ return items[x + y*width]
+ end
+
+ # Set the `value` at row `y` and column `x`
+ #
+ # Require: `x >= 0 and x <= width and y >= 0 and y <= height`
+ #
+ # ~~~
+ # var matrix = new Matrix.identity(2)
+ #
+ # matrix[0, 0] = 0.0
+ # matrix[0, 1] = 0.1
+ # matrix[1, 0] = 1.0
+ # matrix[1, 1] = 1.1
+ #
+ # assert matrix.to_s == """
+ # 0.0 0.1
+ # 1.0 1.1"""
+ # ~~~
+ fun []=(y, x: Int, value: Float)
+ do
+ assert x >= 0 and x < width
+ assert y >= 0 and y < height
+
+ items[x + y*width] = value
+ end
+
+ # Matrix product (×)
+ #
+ # Require: `self.width == other.height`
+ #
+ # ~~~
+ # var m = new Matrix.from([[3.0, 4.0],
+ # [5.0, 6.0]])
+ # var i = new Matrix.identity(2)
+ #
+ # assert m * i == m
+ # assert (m * m).to_s == """
+ # 29.0 36.0
+ # 45.0 56.0"""
+ #
+ # var a = new Matrix.from([[1.0, 2.0, 3.0],
+ # [4.0, 5.0, 6.0]])
+ # var b = new Matrix.from([[1.0],
+ # [2.0],
+ # [3.0]])
+ # var c = a * b
+ # assert c.to_s == """
+ # 14.0
+ # 32.0"""
+ # ~~~
+ fun *(other: Matrix): Matrix
+ do
+ assert self.width == other.height
+
+ var out = new Matrix(other.width, self.height)
+ for j in self.height.times do
+ for i in other.width.times do
+ var sum = items.first.zero
+ for k in self.width.times do sum += self[j, k] * other[k, i]
+ out[j, i] = sum
+ end
+ end
+ return out
+ end
+
+ # Get the transpose of this matrix
+ #
+ # ~~~
+ # var matrix = new Matrix.from([[1.0, 2.0, 3.0],
+ # [4.0, 5.0, 6.0]])
+ # assert matrix.transposed.to_a == [[1.0, 4.0],
+ # [2.0, 5.0],
+ # [3.0, 6.0]]
+ #
+ # var i = new Matrix.identity(3)
+ # assert i.transposed == i
+ # ~~~
+ fun transposed: Matrix
+ do
+ var out = new Matrix(height, width)
+ for k, v in self do out[k.x, k.y] = v
+ return out
+ end
+
+ # Iterate over the values in this matrix
+ fun iterator: MapIterator[MatrixCoordinate, Float] do return new MatrixIndexIterator(self)
+
+ redef fun to_s
+ do
+ var lines = new Array[String]
+ for y in height.times do
+ lines.add items.subarray(y*width, width).join(" ")
+ end
+ return lines.join("\n")
+ end
+
+ redef fun ==(other) do return other isa Matrix and other.items == self.items
+ redef fun hash do return items.hash
+end
+
+private class MatrixIndexIterator
+ super MapIterator[MatrixCoordinate, Float]
+
+ var matrix: Matrix
+
+ redef var key = new MatrixCoordinate(0, 0)
+
+ redef fun is_ok do return key.y < matrix.height
+
+ redef fun item
+ do
+ assert is_ok
+ return matrix[key.y, key.x]
+ end
+
+ redef fun next
+ do
+ assert is_ok
+ var key = key
+ if key.x == matrix.width - 1 then
+ key.x = 0
+ key.y += 1
+ else
+ key.x += 1
+ end
+ end
+end
+
+# Position key when iterating over the values of a matrix
+class MatrixCoordinate
+ # Index of the current column
+ var x: Int
+
+ # Index of the current row
+ var y: Int
+
+ redef fun to_s do return "({x},{y})"
+end
--- /dev/null
+[package]
+name=matrix
+tags=lib
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/matrix/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/matrix/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services on `Matrix` to transform and project 3D coordinates
+module projection
+
+intrude import matrix
+
+redef class Matrix
+
+ # Create an orthogonal projection matrix
+ #
+ # `left, right, bottom, top, near, far` defines the world clip planes.
+ new orthogonal(left, right, bottom, top, near, far: Float)
+ do
+ var dx = right - left
+ var dy = top - bottom
+ var dz = far - near
+
+ assert dx != 0.0 and dy != 0.0 and dz != 0.0
+
+ var mat = new Matrix.identity(4)
+ mat[0, 0] = 2.0 / dx
+ mat[3, 0] = -(right + left) / dx
+ mat[1, 1] = 2.0 / dy
+ mat[3, 1] = -(top + bottom) / dy
+ mat[2, 2] = 2.0 / dz
+ mat[3, 2] = -(near + far) / dz
+ return mat
+ end
+
+ # Create a perspective transformation matrix
+ #
+ # Using the given vertical `field_of_view_y` in radians, the `aspect_ratio`
+ # and the `near`/`far` world distances.
+ new perspective(field_of_view_y, aspect_ratio, near, far: Float)
+ do
+ var frustum_height = (field_of_view_y/2.0).tan * near
+ var frustum_width = frustum_height * aspect_ratio
+
+ return new Matrix.frustum(-frustum_width, frustum_width,
+ -frustum_height, frustum_height,
+ near, far)
+ end
+
+ # Create a frustum transformation matrix
+ #
+ # `left, right, bottom, top, near, far` defines the world clip planes.
+ new frustum(left, right, bottom, top, near, far: Float)
+ do
+ var dx = right - left
+ var dy = top - bottom
+ var dz = far - near
+
+ assert near > 0.0
+ assert far > 0.0
+ assert dx > 0.0
+ assert dy > 0.0
+ assert dz > 0.0
+
+ var mat = new Matrix(4, 4)
+
+ mat[0, 0] = 2.0 * near / dx
+ mat[0, 1] = 0.0
+ mat[0, 2] = 0.0
+ mat[0, 3] = 0.0
+
+ mat[1, 0] = 0.0
+ mat[1, 1] = 2.0 * near / dy
+ mat[1, 2] = 0.0
+ mat[1, 3] = 0.0
+
+ mat[2, 0] = (right + left) / dx
+ mat[2, 1] = (top + bottom) / dy
+ mat[2, 2] = -(near + far) / dz
+ mat[2, 3] = -1.0
+
+ mat[3, 0] = 0.0
+ mat[3, 1] = 0.0
+ mat[3, 2] = -2.0 * near * far / dz
+ mat[3, 3] = 0.0
+
+ return mat
+ end
+
+ # Apply a translation by `x, y, z` to this matrix
+ fun translate(x, y, z: Float)
+ do
+ for i in [0..3] do
+ self[3, i] = self[3,i] + self[0, i] * x + self[1, i] * y + self[2, i] * z
+ end
+ end
+
+ # Apply scaling on `x, y, z` to this matrix
+ fun scale(x, y, z: Float)
+ do
+ for i in [0..3] do
+ self[0, i] = self[0, i] * x
+ self[1, i] = self[1, i] * y
+ self[2, i] = self[2, i] * z
+ end
+ end
+
+ # Create a rotation matrix by `angle` around the vector defined by `x, y, z`
+ new rotation(angle, x, y, z: Float)
+ do
+ var mat = new Matrix.identity(4)
+
+ var mag = (x*x + y*y + z*z).sqrt
+ var sin = angle.sin
+ var cos = angle.cos
+
+ if mag > 0.0 then
+ x = x / mag
+ y = y / mag
+ z = z / mag
+
+ var inv_cos = 1.0 - cos
+
+ mat[0, 0] = inv_cos*x*x + cos
+ mat[0, 1] = inv_cos*x*y - z*sin
+ mat[0, 2] = inv_cos*z*x + y*sin
+
+ mat[1, 0] = inv_cos*x*y + z*sin
+ mat[1, 1] = inv_cos*y*y + cos
+ mat[1, 2] = inv_cos*y*z - x*sin
+
+ mat[2, 0] = inv_cos*z*x - y*sin
+ mat[2, 1] = inv_cos*y*z + x*sin
+ mat[2, 2] = inv_cos*z*z + cos
+ end
+ return mat
+ end
+
+ # Apply a rotation of `angle` radians around the vector `x, y, z`
+ fun rotate(angle, x, y, z: Float)
+ do
+ var rotation = new Matrix.rotation(angle, x, y, z)
+ var rotated = self * rotation
+ self.items = rotated.items
+ end
+end
# This file is part of NIT (http://www.nitlanguage.org).
#
-# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
-#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
}
`}
-redef class String
-
- # Computes the SHA1 of the receiver
- #
- # Returns a digest of 20 bytes as a String,
- # note that all the characters are not necessarily ASCII.
- # If you want the hex string version of the digest, use
- # sha1_to_s.
- #
- # import base64
- # assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI="
- fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
+redef class NativeString
+ private fun sha1_intern(len: Int): NativeString `{
sha1nfo s;
sha1_init(&s);
- sha1_write(&s, String_to_cstring(self), String_length(self));
+ sha1_write(&s, self, len);
uint8_t* digest = sha1_result(&s);
char* digested = malloc(21);
digested[20] = '\0';
- return NativeString_to_s_with_length(digested, 20);
+ return digested;
`}
+end
+
+redef class String
+
+ # Computes the SHA1 of the receiver
+ #
+ # Returns a digest of 20 bytes as a NativeString,
+ # note that all the characters are not necessarily ASCII.
+ # If you want the hex string version of the digest, use
+ # sha1_hexdigest.
+ #
+ # import base64
+ # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8]
+ fun sha1: Bytes do
+ return new Bytes(to_cstring.sha1_intern(bytelen), 20, 20)
+ end
# Computes the SHA1 of the receiver.
#
# Returns a 40 char String containing the Hexadecimal
# Digest in its Char form.
#
- # assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
- fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
- sha1nfo s;
-
- sha1_init(&s);
- sha1_write(&s, String_to_cstring(self), String_length(self));
- uint8_t* digest = sha1_result(&s);
-
- char* ret_str = malloc(41);
- char* hexmap = "0123456789ABCDEF";
-
- int i;
- for(i=0;i<20;i++){
- uint8_t q = digest[i];
- ret_str[i*2] = hexmap[q >> 4];
- ret_str[(i*2)+1] = hexmap[q & 0x0F];
- }
- ret_str[40] = '\0';
-
- return NativeString_to_s_with_length(ret_str, 40);
- `}
-
+ # assert "The quick brown fox jumps over the lazy dog".sha1_hexdigest == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
+ fun sha1_hexdigest: String do return sha1.hexdigest
end
-
resp_map["Connection:"] = "Upgrade"
var key = heads["Sec-WebSocket-Key"]
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- key = key.sha1.encode_base64
+ key = key.sha1.encode_base64.to_s
resp_map["Sec-WebSocket-Accept:"] = key
var resp = resp_map.join("\r\n", " ")
resp += "\r\n\r\n"
The results are displayed in the preview window in order of relevance.
You can search for any word by passing it as an argument, as in `:Nitdoc modulo`.
The Nitdoc command uses the same metadata files as the omnifunc.
-You may want to map the function to a shortcut by adding the following code to `~/.vimrc`.
+You may want to map the command to a shortcut by adding the following code to `~/.vimrc`.
~~~
" Map displaying Nitdoc to Ctrl-D
" Map the NitGitGrep function to Ctrl-G
map <C-g> :call NitGitGrep()<enter>
~~~
+
+## Execute the current file
+
+The command `:NitExecute` calls `nit` to interpret the current file.
+
+If modified, the current buffer is saved to a temporary file before being executed.
+This may cause failures if the current buffer imports modules relative to the source package.
+In such cases, save the file before calling `:NitExecute`.
+
+You may want to map the command to a shortcut by adding the following code to `~/.vimrc`.
+
+~~~
+" Map the NitExecute function to Ctrl-F
+map <C-f> :NitExecute<enter>
+~~~
redraw!
endfun
+" Call `nit` on the current file
+fun NitExecute()
+ let path = expand('%')
+
+ if &modified
+ let path = tempname() . '.nit'
+ execute '%write '. path
+ endif
+
+ execute '!nit "' . path . '"'
+endfun
+command NitExecute call NitExecute()
+
if !exists("g:nit_disable_omnifunc") || !g:nit_disable_omnifunc
" Activate the omnifunc on Nit files
autocmd FileType nit set omnifunc=NitOmnifunc
# Placeholder to include additional things before the `</head>`.
var more_head = new Template
+ # Relative path to the root directory (with the index file).
+ #
+ # Use "" for pages in the root directory
+ # Use ".." for pages in a subdirectory
+ var rootpath: String
+
redef init
do
add """
<head>
<meta charset="utf-8">
<link rel="stylesheet" media="all" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
- <link rel="stylesheet" media="all" href="style.css">
+ <link rel="stylesheet" media="all" href="{{{rootpath / "style.css"}}}">
"""
add more_head
</div>
<div class='collapse navbar-collapse' id='topmenu-collapse'>
<ul class='nav navbar-nav'>
- <li><a href="index.html">Catalog</a></li>
+ <li><a href="{{{rootpath / "index.html"}}}">Catalog</a></li>
</ul>
</div>
</div>
# Compute information and generate a full HTML page for a package
fun package_page(mpackage: MPackage): Writable
do
- var res = new CatalogPage
+ var res = new CatalogPage("..")
var score = score[mpackage].to_f
var name = mpackage.name.html_escape
res.more_head.add """<title>{{{name}}}</title>"""
if cat == null then cat = t
tag2proj[t].add mpackage
t = t.html_escape
- ts2.add "<a href=\"index.html#tag_{t}\">{t}</a>"
+ ts2.add "<a href=\"../index.html#tag_{t}\">{t}</a>"
end
res.add_list(ts2, ", ", ", ")
end
var t = "none"
cat = t
tag2proj[t].add mpackage
- res.add "<a href=\"index.html#tag_{t}\">{t}</a>"
+ res.add "<a href=\"../index.html#tag_{t}\">{t}</a>"
end
if cat != null then cat2proj[cat].add mpackage
score += ts2.length.score
fun li_package(p: MPackage): String
do
var res = ""
- var f = "{p.name}.html"
+ var f = "p/{p.name}.html"
res += "<a href=\"{f}\">{p}</a>"
var d = p.mdoc_or_fallback
if d != null then res += " - {d.html_synopsis.write_to_string}"
res.add "</tr></thead>"
for p in mpackages do
res.add "<tr>"
- res.add "<td><a href=\"{p.name}.html\">{p.name}</a></td>"
+ res.add "<td><a href=\"p/{p.name}.html\">{p.name}</a></td>"
var maint = "?"
if p.maintainers.not_empty then maint = p.maintainers.first
res.add "<td>{maint}</td>"
end
var out = opt_dir.value or else "catalog.out"
-out.mkdir
+(out/"p").mkdir
# Generate the css (hard coded)
var css = """
for p in model.mpackages do
# print p
- var f = "{p.name}.html"
+ var f = "p/{p.name}.html"
catalog.package_page(p).write_to_file(out/f)
end
# INDEX
-var index = new CatalogPage
+var index = new CatalogPage("")
index.more_head.add "<title>Packages in Nit</title>"
index.add """
# PEOPLE
-var page = new CatalogPage
+var page = new CatalogPage("")
page.more_head.add "<title>People of Nit</title>"
page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
page.add "<h2>By Maintainer</h2>\n"
# TABLE
-page = new CatalogPage
+page = new CatalogPage("")
page.more_head.add "<title>Projets of Nit</title>"
page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
page.add "<h2>Table of Projets</h2>\n"
FlatString = 18
Calls to first_byte on FlatString 153
Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
Length of travel for index distribution:
* null = 20 => occurences 83.333%, cumulative 83.333%
* 1 = 8 => occurences 21.053%, cumulative 73.684%
if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self)
if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
+ if name == "Array[Int]" then return new Array[Int].from_deserializer(self)
if name == "Array[Match]" then return new Array[Match].from_deserializer(self)
if name == "Array[nullable Match]" then return new Array[nullable Match].from_deserializer(self)
return super
--- /dev/null
+0x0b
+0x1f
+0x4d
FlatString = 18
Calls to first_byte on FlatString 153
Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
Length of travel for index distribution:
* 0 = 20 => occurences 83.333%, cumulative 83.333%
* 1 = 8 => occurences 21.053%, cumulative 73.684%
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var s = "0B1F4D".hexdigest_to_bytes
+
+for i in s do print i