Skip to content

Commit

Permalink
Merge branch 'main' into beta
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed Jun 10, 2024
2 parents c90b81a + 48639c0 commit 10caee2
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
shell: bash
run: |
if [[ "${{ runner.os }}" == "Windows" ]] ; then
choco install --no-progress wget
choco install wget -y --no-progress
elif [[ "${{ runner.os }}" == "macOS" ]] ; then
brew install pixman freetype harfbuzz zlib
else
Expand Down
72 changes: 72 additions & 0 deletions .github/workflows/lint_commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Based on SerenityOS commit linter:
# https://github.com/SerenityOS/serenity/blob/master/.github/workflows/lintcommits.yml

name: Commit linter
on: [pull_request_target]
jobs:
lint_commits:
runs-on: ubuntu-22.04
if: always() && github.repository == 'aseprite/laf'
steps:
- name: Lint PR commits
uses: actions/github-script@v7
with:
script: |
const rules = [
{
pattern: /^[^\r]*$/,
error: "Commit message contains CRLF line breaks (only unix-style LF linebreaks are allowed)",
},
{
pattern: /^.+(\r?\n(\r?\n.*)*)?$/,
error: "Empty line between commit title and body is missing",
},
{
pattern: /^.{0,72}(?:\r?\n(?:(.{0,72})|(.*?([a-z]+:\/\/)?(([a-zA-Z0-9_]|-)+\.)+[a-z]{2,}(:\d+)?([a-zA-Z_0-9@:%\+.~\?&/=]|-)+).*?))*$/,
error: "Commit message lines are too long (maximum allowed is 72 characters, except for URLs)",
},
{
pattern: /^.+[^.\n](\r?\n.*)*$/,
error: "Commit title ends in a period",
},
{
pattern: /^((?!Signed-off-by: )[\s\S])*$/,
error: "Commit body contains a Signed-off-by tag",
},
];
const { repository, pull_request } = context.payload;
// NOTE: This maxes out at 250 commits. If this becomes a problem, see:
// https://octokit.github.io/rest.js/v18#pulls-list-commits
const opts = github.rest.pulls.listCommits.endpoint.merge({
owner: repository.owner.login,
repo: repository.name,
pull_number: pull_request.number,
});
const commits = await github.paginate(opts);
const errors = [];
for (const { sha, commit: { message } } of commits) {
const commitErrors = [];
for (const { pattern, error } of rules) {
if (!pattern.test(message)) {
commitErrors.push(error);
}
}
if (commitErrors.length > 0) {
const title = message.split("\n")[0];
errors.push([`${title} (${sha}):`, ...commitErrors].join("\n "));
}
}
if (errors.length > 0) {
core.setFailed(`One or more of the commits in this PR do not match the code submission policy:\n\n${errors.join("\n")}`);
}
- name: Comment on PR
if: ${{ failure() && !github.event.pull_request.draft }}
uses: unsplash/comment-on-pr@a9bf050e744c8282dee4bb0dbcf063186d8316c4
env:
GITHUB_TOKEN: ${{ secrets.LINT_COMMIT_TOKEN }}
with:
msg: "Hi there!\n\nOne or more of the commit messages in this PR do not match our [code submission policy](https://github.com/aseprite/laf/blob/main/CONTRIBUTING.md), please check the `lint_commits` CI job for more details on which commits were flagged and why.\nPlease do not close this PR and open another, instead modify your commit message(s) with [git commit --amend](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/changing-a-commit-message) and force push those changes to update this PR."
22 changes: 21 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Licensing

By submitting a pull request, you represent that you have the right to
license your contribution to the Laf project owners and the community,
agree by submitting the patch that your contributions are licensed
and agree by submitting the patch that your contributions are licensed
under the [MIT license](https://raw.githubusercontent.com/aseprite/laf/main/LICENSE.txt)
terms.

# Code submission policy

We have some rules for commits that are contributed:

* Split your changes in the most atomic commits possible: one commit
for feature, or fix.
* Rebase your commits to the `main` branch (or `beta` if you are
targeting the beta version).
* Wrap your commit messages at 72 characters.
* The first line of the commit message is the subject line.
* Write the subject line in the imperative mood, e.g. "Fix something",
not "Fixed something".
* For platform-specific commits start the subject line using
`[win]`, `[osx]`, or `[x11]` prefixes.
* Check the spelling of your code, comments and commit messages.
* We're using some C++17 features, targeting macOS 10.9 mainly as the
oldest platform (and the one limiting us to newer C++ standards).
15 changes: 14 additions & 1 deletion base/file_handle.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// LAF Base Library
// Copyright (c) 2020-2021 Igara Studio S.A.
// Copyright (c) 2020-2024 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
Expand Down Expand Up @@ -55,6 +55,19 @@ FILE* open_file_raw(const string& filename, const string& mode)
#endif
}

FILE* reopen_file_raw(const string& filename, const string& mode, FILE* stream)
{
#if LAF_WINDOWS
return _wfreopen((!filename.empty() ? from_utf8(filename).c_str(): nullptr),
from_utf8(mode).c_str(),
stream);
#else
return freopen((!filename.empty() ? filename.c_str(): nullptr),
mode.c_str(),
stream);
#endif
}

FileHandle open_file(const string& filename, const string& mode)
{
return FileHandle(open_file_raw(filename, mode), fclose_if_valid);
Expand Down
3 changes: 2 additions & 1 deletion base/file_handle.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// LAF Base Library
// Copyright (c) 2020 Igara Studio S.A.
// Copyright (c) 2020-2024 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
Expand All @@ -18,6 +18,7 @@ namespace base {
using FileHandle = std::shared_ptr<FILE>;

FILE* open_file_raw(const std::string& filename, const std::string& mode);
FILE* reopen_file_raw(const std::string& filename, const std::string& mode, FILE* stream);
FileHandle open_file(const std::string& filename, const std::string& mode);
FileHandle open_file_with_exception(const std::string& filename, const std::string& mode);
FileHandle open_file_with_exception_sync_on_close(const std::string& filename, const std::string& mode);
Expand Down
113 changes: 113 additions & 0 deletions base/tok.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// LAF Base Library
// Copyright (c) 2024 Igara Studio S.A.
// Copyright (c) 2020 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
//
// Based on https://github.com/dacap/tok

#ifndef BASE_TOK_H_INCLUDED
#define BASE_TOK_H_INCLUDED
#pragma once

#include <iterator>
#include <string>

namespace base {
namespace tok {

struct ignore_empties { enum { allow_empty = false }; };
struct include_empties { enum { allow_empty = true }; };

template<typename T, typename EmptyPolicy>
class token_iterator {
public:
using iterator_category = std::forward_iterator_tag;
using internal_iterator = typename T::const_iterator;
using char_type = typename T::value_type;
using value_type = typename std::remove_const<T>::type;
using difference_type = typename T::difference_type;
using pointer = T*;
using reference = T&;
using const_reference = const T&;

token_iterator() = delete;
token_iterator(const token_iterator&) = default;
token_iterator(const internal_iterator& begin,
const internal_iterator& end,
char_type chr) :
begin_(begin),
inter_(begin),
end_(end),
chr_(chr) {
operator++(); // Find first word to fill "str_" field
}

token_iterator& operator++() {
if constexpr (EmptyPolicy::allow_empty) {
if (inter_ != end_ && *inter_ == chr_) {
++inter_;
}
}
else {
while (inter_ != end_ && *inter_ == chr_) {
++inter_;
}
}
begin_ = inter_;
while (inter_ != end_ && *inter_ != chr_) {
++inter_;
}
str_.assign(begin_, inter_);
return *this;
}

const_reference operator*() {
return str_;
}

bool operator!=(const token_iterator& that) const {
return (begin_ != that.end_);
}

private:
internal_iterator begin_, inter_, end_;
char_type chr_;
value_type str_;
};

template<typename T, typename Empties>
class token_range {
public:
using char_type = typename T::value_type;
using iterator = token_iterator<T, Empties>;

token_range(const T& str, char_type chr) : str_(str), chr_(chr) { }

iterator begin() const { return iterator(str_.begin(), str_.end(), chr_); }
iterator end() const { return iterator(str_.end(), str_.end(), chr_); }

private:
const T& str_;
char_type chr_;
};

template<typename T>
token_range<T, ignore_empties>
split_tokens(const T& str,
typename T::value_type chr) {
return token_range<T, ignore_empties>(str, chr);
}

template<typename T>
token_range<T, include_empties>
csv(const T& str,
typename T::value_type chr = ',') {
return token_range<T, include_empties>(str, chr);
}

} // namespace tok
} // namespace base

#endif
44 changes: 44 additions & 0 deletions base/tok_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// LAF Base Library
// Copyright (c) 2024 Igara Studio S.A.
// Copyright (c) 2020 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
//
// Based on https://github.com/dacap/tok

#include <gtest/gtest.h>

#include <iostream>
#include <string>
#include <vector>

#include "base/tok.h"

TEST(Tok, SplitTokens)
{
int i = 0;
auto a_result = std::vector<std::string>{ "This", "is", "a", "phrase.", "Several", "whitespaces", "are", "ignored." };
std::string a = "This is a phrase. Several whitespaces are ignored.";
for (auto& tok : base::tok::split_tokens(a, ' ')) {
std::cout << "\"" << tok << "\"\n";
EXPECT_EQ(tok, a_result[i++]);
}
}

TEST(Tok, Csv)
{
int i = 0;
auto b_result = std::vector<std::string>{ "In comma", "separated", "", "values", "", "", "empties are included" };
std::string b = "In comma,separated,,values,,,empties are included";
for (auto& tok : base::tok::csv(b, ',')) {
std::cout << "\"" << tok << "\"\n";
EXPECT_EQ(tok, b_result[i++]);
}
}

int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit 10caee2

Please sign in to comment.